Vue进阶 | 从源码来看$nextTick的原理

124 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

说说$nextTick的原理?

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

一、原理

  • 当数据的值发生变化,Vue并不会立刻更新DOM,而是将数据变化的 watcher 放入一个异步操作队列中
  • 有去重操作,多次触发只会入队一次,避免非必要的DOM操作
  • 等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。

nextTick会在DOM渲染之后被触发,在修改数据之后立即调用 this.$nextTick(callback) ,就可以获取最新的DOM节点

源码部分的理解:

官方源码指路:github.com/vuejs/vue/b…

  1. 执行环境检测(降级处理):

    首先会检测当前的执行环境是否支持Promise.then,MutationObserver(监听节点、DOM变化),setImmediate,setTimeout。

    进行降级处理的目是将flushCallbacks函数放入微任务或者宏任务。支持哪种方式就用哪种来触发执行回调函数,优先执行微任务(因为宏任务耗费的时间⼤于微任务)

    • 微任务: Promise.then、MutationObsever
    • 宏任务: setTimeout、setImmediate;

    注:如果前三个都不支持,最后选择setTimeout,执行setTimeout(flushCallbacks, 0)

  2. 执行回调队列中的每一个回调:

    • 执行环境检测后,会得到⼀个延迟回调函数timerFunc,随后开始执行 nextTick 函数
    • 将回调函数放入回调队列,遍历执行回调函数
    • 如果没有提供回调,并且支持Promise,会返回一个Promise

image.png

image.png

二、使用方法

this.value = '已修改'  
// 此时DOM未更新,依旧是修改前的状态 
this.$nextTick(() => {
// 此时DOM已更新,可以获取变化后的 DOM

})

或:

this.value = '已修改' 
// 此时DOM未更新
await this.$nextTick() 
// 此时DOM已更新,可以获取变化后的 DOM

注:全局 API 使用 Vue.nextTick()

三、应用场景

  • 在数据变化后要立即执行某个操作时
  • 在生命周期created()中进行的DOM操作要放在Vue.nextTick()的回调函数中(因为此阶段DOM还未进行渲染)