nextTick
是 Vue.js 中常见的一种异步更新 DOM 的机制。实现原理主要涉及异步更新队列和事件循环机制。
-
异步更新队列:
- Vue 在更新 DOM 时是异步执行的。一旦侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
- 如果同一个 Watcher 被多次触发,只会被推入到队列中一次,避免不必要的计算和 DOM 操作。
- 在下一个事件循环“tick”中,Vue 刷新队列并执行实际(已去重的)工作。
-
事件循环机制:
- Vue 内部会优先使用微任务(如
Promise.then
和MutationObserver
)来实现异步更新,如果执行环境不支持,则会采用宏任务(如setImmediate
和setTimeout
)。 - 当数据变化时,Vue 会将更新操作推入微任务队列,确保在当前事件循环结束后立即执行这些更新。
- Vue 内部会优先使用微任务(如
-
实现原理:
nextTick
会将传入的回调函数包装成异步任务,并优先选择微任务来执行,在数据更新触发时,将回调塞入到微任务队列相应的位置,以确保尽快执行,不会被去重滞后。
-
使用
nextTick(callback)
:- 为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用
Vue.nextTick(callback)
。 - 这样回调函数将在 DOM 更新完成后被调用。
- 示例:
<div id="example">{{ message }}</div> var vm = new Vue({el: '#example',data: {message: '123'} }); vm.message = 'new message'; // 更改数据 vm.$el.textContent === 'new message'; // false Vue.nextTick(function () {vm.$el.textContent === 'new message'; // true });
- 为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用
-
在组件内使用
nextTick()
:nextTick()
实例方法特别方便,不需要全局 Vue,并且回调函数中的this
将自动绑定到当前的 Vue 实例上。- 示例:
Vue.component('example', {template: '<span>{{ message }}</span>',data: function () {return { message: '未更新' };},methods: {updateMessage: function () {this.message = '已更新';console.log(this.$el.textContent); // => '未更新'this.$nextTick(function () {console.log(this.$el.textContent); // => '已更新'});}} });
-
使用
async/await
:- 因为
nextTick()
返回一个 Promise 对象,可以使用新的 ES2017async/await
语法完成相同的事情:methods: {updateMessage: async function () {this.message = '已更新';console.log(this.$el.textContent); // => '未更新'await this.$nextTick();console.log(this.$el.textContent); // => '已更新'} }
- 因为
nextTick
让我们在数据变化后等待 DOM 更新完成,非常有用。