Vue 中 nextTick的作用

143 阅读4分钟

Vue 中 nextTick的作用

在 Vue 中,nextTick是一个非常重要的工具,它允许我们在 DOM 更新后执行某些操作。简单来说,nextTick 让我们在 Vue 完成 DOM 更新后执行代码。它通常用于获取更新后的 DOM 状态或执行需要 DOM 更新后的逻辑。

本文目的:它的作用,为什么要用它,它的原理,常见原理理解误区

nextTick 的作用

Vue 是一个响应式的框架,当响应式数据发生变化时,Vue 会异步地更新 DOM。这是为了提高性能,避免频繁的 DOM 操作导致不必要的渲染。由于这种一步更新的特性,某些时候我们需要确保在 DOM 更新后执行特定的代码,比如获取更新后的 DOM 元素、操作 DOM、执行某些与视图相关的任务等。

这时,nextTick 就派上了用场。它会将一个回调函数推入到下一个事件循环队列(即DOM更新后执行),确保代码在 DOM 更新后执行。

nextTick 的使用场景

1.获取更新后的 DOM 状态 如果在某个数据变化后需要获取更新后的 DOM 状态,nextTick 就可以确保获取到的是最新的 DOM。 2.执行依赖于 DOM 更新的操作 如果某些操作(如动画、滚动、焦点等)依赖于 DOM 的渲染结果,你需要等到 DOM 完全更新后再执行。这时,nextTick 就能确保代码在合适的时机执行。 例如某个输入框组件需要在某个DOM更新后进行聚焦。 3.与外部库配合使用 当与一些第三方库(例如JQuery、D3.js等)结合使用时,这些库通常依赖于 DOM 元素的存在或状态。因为 Vue 更新 DOM 是异步的额,如果在 Vue 更新 DOM 之前执行这些库的操作,可能会遇到 DOM 还没更新的情况。使用 nextTick 可以确保第三方库的操作发生在 Vue 更新之后,避免 DOM 操作出错。

nextTick 的工作原理

Vue的DOM更新是异步的,Vue会把响应式数据里修改触发视图修改或者回调函数,统一存储到一个数组队列里,nextTick传的回调函数也会被传进来这个数组队列。

  • 而这个数组队列的执行时机,是根据浏览器环境选择放到宏任务队列里或者微任务队列里,一般默认都放到微任务队列里。

  • 也就是Promise.resolve().then()的这个回调里,然后在事件循环轮到这次微任务的时候,会直接按顺序执行这个数组队列

  • 同时响应式数据修改的回调函数是比nextTick的回调函数添加的更早的,并且响应式数据修改时是会经历patch 和diff修改真实DOM属性的,所以nextTick的回调函数是可以获取之后DOM的属性或者修改的。

至于为什么Vue的DOM更新是异步的。是为了更快的渲染视图同时避免不必要的渲染。

1.如果把这些任务放到宏任务里,按照js的事件循环机制,在当前同步代码执行完之后,先清空当前微任务队列,然后UI会先进行一次渲染,然后才是下一个宏任务,也就是更新视图的代码了,并且在这一轮再进行一次更新。 2.至于避免不必要的渲染,是因为把所有DOM更新修改的操作都统一放到一个队列里去执行了,例如一个计时器,点击一次修改一百次变量a,如果自己手动通过ref去修改这个a,每次点击每次都要进行一百次渲染很浪费性能,而如果只拿最后一次结果来显示,就节省了很多不必要的渲染,也就是合并了操作DOM的行为,最后由浏览器统一渲染。

执行顺序: 1.Vue响应式数据发生变化,触发DOM更新。 2.Vue将更新操作加入到微任务队列。 3.微任务队列中的回调函数执行(虚拟DOM更新、差异计算等)(修改真实DOM的属性和获取,但是还没渲染到页面上)。 4.微任务执行完毕后,浏览器进行渲染,显示更新的DOM。

(常见理解误区,啊,数据修改触发的回调更新视图是放在微任务里的,nextTick的回调函数也是同一个微任务队列里的,nextTick怎么可以拿到渲染后DOM的属性的,其实DOM还没渲染,只是真实DOM树发生了修改)(同时,手动通过$ref去修改DOM属性的不会去放到Vue里面的异步更新DOM里面,因为异步更新DOM只针对由响应式数据修改后引发的视图修改,也就是 patch 和 diff)