this.$nextTick()的原理与使用场景

this.$nextTick()的原理与使用场景

遇到这个方法的时候,比较困惑,搜集一些资料,总结一下其原理和用途

官网说法:

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

获取更新后的DOM,言外之意就是什么操作需要用到了更新后的DOM,
而不能使用之前的DOM,
所以就衍生出了这个获取更新后的 DOM的Vue方法

DOM是如何更新的呢?

1.原理

Vue实现响应式并不是数据发生变化之后DOM立即变化,而是异步执行DOM更新的。

异步执行的运行机制是什么样的?阮一峰老师是这样总结的:

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

主线程不断执行任务、获取任务、执行任务……的过程叫做事件循环

vue异步更新的原理:

1.修改 Vue 中的 Data 时,就会触发所有和这个 Data 相关的 Watcher 进行更新。

2.首先,会将所有的 Watcher 加入队列 Queue。

3.然后,调用 nextTick 方法,执行异步任务。

4.在异步任务的回调中,对 Queue 中的 Watcher 进行排序,然后执行对应的 DOM 更新。

// 当一个 Data 更新时,会依次执行以下代码
// 1. 触发 Data.set
// 2. 调用 dep.notify 订阅者
// 3. Dep 会遍历所有相关的 Watcher 执行 update 方法
class Watcher {
  // 4. 执行更新操作
  update() {
    queueWatcher(this);
  }
}

const queue = [];

function queueWatcher(watcher: Watcher) {
  // 5. 将当前 Watcher 添加到异步队列
  queue.push(watcher);
  // 6. 执行异步队列,并传入回调
  nextTick(flushSchedulerQueue);
}

// 更新视图的具体方法
function flushSchedulerQueue() {
  let watcher, id;
  // 排序,先渲染父节点,再渲染子节点
  // 这样可以避免不必要的子节点渲染,如:父节点中 v-if 为 false 的子节点,就不用渲染了
  queue.sort((a, b) => a.id - b.id);
  // 遍历所有 Watcher 进行批量更新。
  for (index = 0; index < queue.length; index++) {
    watcher = queue[index];
    // 更新 DOM
    watcher.run();
  }
}

2.this.$nextTick()的使用场景

什么时候需要用Vue.nextTick():

  1. 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
  2. 在数据变化后要执行的某个操作,当你设置 vm.someData = ‘new value’,DOM并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用
  3. mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted:

参考文章:https://www.jianshu.com/p/46c9d777cab1
https://www.cnblogs.com/pleaseAnswer/p/13566987.html

上一篇:$nextTick的使用


下一篇:vue方法