前言
对于新人朋友而言,nextTick可能是一个较为陌生的API,接下来我们从Vue2和Vue3的nextTick的用法进行示例讲解。
一、关于nextTick
nextTick本身是一种API,使用方法也很简单,主要就是回调,了解它的原理之前我们能需要对JavaScript的异步运行机制有一定的了解。 首先我们需要认识到,Vue实现响应式的异步更新,也不是数据(data)发生变化后立即产生的变化。处于对性能的考量,每一次数据发生变化,DOM不会立即更新,而是说在Vue中只要观察到data的变化,即会立即将事件缓存到一个事件循环中去,避免不必要的DOM操作,但是若是想要在数据发生变化之后立即获取数据或者操作一些什么,这个时候我们就需要调用到nextTick。
二、使用
接下来我们通过两个案例来看一下nextTick的具体使用方法,然后我们再来做一个总结。
1.示例一:获取数据更新后的DOM节点的值
下面的案例很简单,只是一个简单的更换msg的操作,点击按钮将msg从Hello换为Hi;然后打印出ref_p的值。
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">
<p ref="ref_p">{{msg}}</p>
<input @click="msgFn" type="button" value="按钮" />
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
msg: 'Hello!'
}
},
methods: {
msgFn() {
this.msg = 'Hi';
console.log(this.$refs['ref_p'].innerHTML);
}
},
}).mount('#app')
</script>
点击按钮之前
点击按钮之后 然后我们查看打印出来的ref_p的值: 我们发现一个问题,右边打印出来的值任然是变化之前的Hello,就是说页面视图变化了,但是打印的数据没有变化。那么我们来看看使用nextTick之后的结果:
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">
<p ref="ref_p">{{msg}}</p>
<input @click="msgFn" type="button" value="按钮" />
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
msg: 'Hello!'
}
},
methods: {
msgFn() {
this.msg = 'Hi';
this.$nextTick(() => {
console.log(this.$refs['ref_p'].innerHTML);
})
}
},
}).mount('#app')
</script>
然后点击按钮之后: 可以发现此时的ref_p的节点值就变成了Hi,此时就达到了预期的效果。下面看一下示例2:在setup中调用nextTick;
2.示例二:在setup中调用nextTick
下面的案例也很简单,也是点击按钮改变msg的值,获取DOM更新后的值:
<div class="nt">
<p ref="p_msg">{{ msg }}</p>
<button @click="test">点击</button>
</div>
</template>
<script lang="ts" setup>
import { ref, nextTick } from "vue";
const msg = ref("测试1")
const p_msg = ref(null);
const test = async () => {
msg.value = "结果1";
console.log("msg的value:", msg.value)
console.log("更新前的p_msg的innerHtml:", p_msg.value.innerHTML);
await nextTick();
console.log("更新后的p_msg的innerHtml:", p_msg.value.innerHTML);
};
</script>
注意一下此处的nextTick的使用,先导入nextTick,因为是一个异步更新的任务,所以我们也可以使用async/await,
然后我们点击按钮触发事件(此处为点击后): 视图已经发生了变化,从“测试1”变为了“结果1”; 那么打印的结果呢:
可以发现更新后的结果“结果1”,实现了异步更新的效果。
三,为什么nextTick可以拿到DOM更新后的数据
1,修改Vue的data,Vue会将所有与这个data更新的有关watcher加入队列;
2,调用nextTick方法,传入用于DOM更新的回调函数;
3, 执行nextTick时若遇到异步代码,则会将更新DOM的操作加入异步任务队列。
4,当前执行栈中的同步任务执行完成,异步任务队列中用于DOM更新的异步代码才会被拿到执行栈中,所以直接获取DOM同步操作去拿异步更新DOM数据不可行。
5,然后nextTick也会作为对应的回调加入任务队列。
6,队列先进先出,包含DOM更新操作的异步任务会先执行,执行结束就生成新DOM,接下来再执行下一个异步任务的时候就拿到了更新后的DOM。
三、 总结
关于nextTick的调用,我们要先理解Vue执行DOM的更新是异步的,在Vue中只要是观察到data的更新,即会把事件缓存到一个事件循环里,以避免不必要的DOM操作,简单理解就是在DOM渲染之后自动执行回调函数,可以实现在数据变化之后立刻获取数据或者操作一些什么。
|