返回

Vue nextTick 的正确姿势是什么?是时候该掌握 nextTick 了!

前端

我们日常开发中,通常会使用 Vue 的 nextTick 方法在 DOM 更新后运行函数。我们通常认为 nextTick 的原理是:在当前任务结束后,DOM 更新完毕后,异步队列清空时执行(即代码执行完毕之后执行)。

因此,有以下代码:

vm.$nextTick(() => {
    console.log('DOM 更新完毕');
});
console.log('执行完毕');

我们猜测会依次打印:1、2、3。但是实际效果中,只会输出一次:3。为什么会出现这样的情况?我们来一探究竟。

Vue 中的数据更新机制

我们在 Vue 中初始化一个变量 msg 为 0,我们定义 watch 监听 msg,实际上会被 Vue 这样调用 vm.$watch(keyOrFn, handler, options)$watch 是我们初始化的时候调用的,这样会执行 handler 函数。

// Vue 实例初始化时执行
const vm = new Vue({
    data() {
        return {
            msg: 0
        };
    },
    watch: {
        msg(newValue, oldValue) {
            // msg 发生变化时触发
            console.log(`监听到 msg 的变化,现在 msg 为:${newValue}`);
        }
    }
});

// 开始手动更新 msg 的值
vm.msg = 1;

实际上,vm.msg 的值并不会立刻更新,而是变为一个任务先放入消息队列中,然后在执行栈清空后,这个任务会被执行,然后更新 msg 的值。此时,我们的 watch 函数被调用,在监听到值变化的时候,我们在 watch 中执行了一个 vm.$nextTick,然后将函数放入消息队列中。

在本次任务执行完毕后,所有进入消息队列的任务都会依次执行,其中包括:vm.msg 的值更新、vm.$nextTick 函数的执行。但是 vm.$nextTick 的执行实际上是在 msg 的值更新之后,所以 watch 函数会被再次调用,所以 console.log 输出 3。

这就是 为什么我们看到的输出只有 3 的原因。因为 msg 的值更新和 vm.$nextTick 函数都是异步的,而 console.log('执行完毕'); 是同步执行的,所以 console.log('执行完毕'); 就会先执行。

如何正确使用 nextTick?

1. 用于 DOM 更新后操作

在需要在 DOM 更新完毕后执行操作时,可以使用 nextTick。例如,在以下场景中,可以使用 nextTick

  • 需要在 DOM 元素被渲染后获取其尺寸;
  • 需要在 DOM 元素被渲染后执行动画;
  • 需要在 DOM 元素被渲染后执行表单验证。

2. 确保回调函数在组件更新完毕后执行

在组件更新完毕后执行回调函数时,可以使用 nextTick。例如,在以下场景中,可以使用 nextTick

  • 需要在组件更新完毕后获取组件的最新数据;
  • 需要在组件更新完毕后执行组件的某个方法;
  • 需要在组件更新完毕后执行组件的某个生命周期钩子函数。

3. 避免无限循环

如果在 nextTick 的回调函数中再次调用 nextTick,可能会导致无限循环。因此,在使用 nextTick 时,应避免在回调函数中再次调用 nextTick

4. 避免在销毁的组件中使用 nextTick

在销毁的组件中使用 nextTick 可能会导致错误。因此,在销毁组件之前,应确保不再使用 nextTick

总结

nextTick 是一种异步方法,可以在 DOM 更新完毕后执行函数。在需要在 DOM 更新完毕后执行操作时,可以使用 nextTick。但是,在使用 nextTick 时,应注意避免无限循环和在销毁的组件中使用 nextTick