这一节了解一下Vue3中的nextTick,nextTick是等待DOM更新完成之后执行回调的函数。Vue的响应式数据变更不会立刻更新DOM,是异步批量更新,nextTick就是用来在DOM渲染完毕后再执行代码。简单总结:
API:
import { nextTick } from 'vue' // Promise写法(async await) await nextTick() // 回调写法 nextTick(() => { // DOM更新完成 })场景
1 数据更新后读取DOM:获取更新后的文本、尺寸、位置等。
2 v-if/v-show 切换后操作元素:元素刚渲染出来时DOM尚未就绪。
3 列表动态增删后聚焦/滚动:v-for新增项后自动聚焦或滚动到末尾。
栗子:
<template> <div> <button @click="showInput">显示输入框,并自动聚焦</button> <input v-if="flag" ref="inputRef" placeholder="我会自动聚焦" /> </div> </template> <script setup lang="ts"> import { ref, nextTick } from 'vue' const flag = ref(false) const inputRef = ref<HTMLInputElement | null>(null) const showInput = async () => { flag.value = true await nextTick() inputRef.value?.focus() } </script><template> <div> <button @click="addMsg">新增一条消息</button> <div class="msg-box" ref="boxRef"> <div class="msg-item" v-for="item in msgList" :key="item.id"> {{ item.content }} </div> </div> </div> </template> <script setup lang="ts"> import { ref, nextTick } from 'vue' const msgList = ref([ { id: 1, content: '消息1' }, { id: 2, content: '消息2' }, ]) const boxRef = ref<HTMLDivElement | null>(null) const addMsg = async () => { const newId = Date.now() msgList.value.push({ id: newId, content: `新消息:${newId}` }) await nextTick() if (boxRef.value) { boxRef.value.scrollTop = boxRef.value.scrollHeight } } </script> <style scoped> .msg-box { width: 300px; height: 200px; border: 1px solid #ccc; overflow-y: auto; } .msg-item { padding: 4px; } </style>注意
1 仅返回Promise:Vue3的nextTick()不再支持传入回调函数,必须用await或.then()。
2 避免滥用:能用声明式模板/计算属性解决的问题,不要用nextTick手动操作DOM。
3 错误处理:await nextTick()可能因组件卸载等抛出异常,建议用try/catch包裹。