对Vue中nextTick的理解

Vue中nextTick

一、nextTick是什么?

官方定义:

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

我们可以理解成Vue在更新DOM时是异步执行的。当数据发生改变时,Vue将开启一个异步更新队列,视图需要等所有数据改变完之后,再统一进行更新。
当数据更新了,在DOM中渲染后,自动执行该函数。

代码示例

<template>
  <div class="app">
      <div ref="msgDiv">{
   
   {msg}}</div>
      <div v-if="msg1">{
   
   {msg1}}</div>
      <div v-if="msg2">{
   
   {msg2}}</div>
      <div v-if="msg3">{
   
   {msg3}}</div>
      <button @click="changeMsg">点击我</button>
  </div>
</template>
<script>
export default {
     
     
    name: 'vueDemo',
    data() {
     
     
        return {
     
     
            msg: 'hello, my brother',
            msg1: '',
            msg2: '',
            msg3: '',
        }
    },
    methods: {
     
     
        changeMsg() {
     
     
            this.msg = 'hello, my Sean'         
            this.msg1 = this.$refs.msgDiv.innerHTML     
            this.$nextTick(() => {
     
     
                this.msg2 = this.$refs.msgDiv.innerHTML
            })                                         
            this.msg3 = this.$refs.msgDiv.innerHTML                      
        }
    }
}
</script>

点击前
在这里插入图片描述
点击后
在这里插入图片描述
原因是DOM的更新时异步的,msg1和msg3还是之前的数据,而msg2显示的是DOM更新过后的数据。

二、使用场景

  • 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。
    created()钩子函数执行的时候,DOM并没有进行任何渲染,而此时进行DOM操作是徒劳的,所以这个时候一定要将执行DOM操作的js代码放入this.nextTick()的回调函数中。而mounted()钩子函数执行时,所有DOM的挂载和渲染都已完成,此时可以在该钩子函数中进行DOM操作。
  • 在数据变化后要执行的某个操作,需要使用随数据的改变而改变的DOM结构时,这个操作应该放入this.nextTick()中。

Vue异步执行DOM更新,只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个watcher被多次处罚,最会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作上非常重要。
然后,在下一个时间循环“tick”中,Vue刷新队列并执行实际(已经去重的)工作。Vue在内部尝试对队列使用原生的Promise.thenMessageChannel,如果执行环境不支持,会采用setTimeout(fn, 0)代替。

图片来源于网络

事件循环

第一个tick(图中的第一个步骤,即“本次更新循环”):

  1. 首先修改数据,这是同步任务。同一事件循环的所有同步任务都在主线程上执行,形成一个执行栈,此时还未涉及DOM。
  2. Vue开启一个异步队列,并缓冲在此事件循环中所有的数据改变。如果同一个watcher被多次触发,只会被推入到队列中一次。

第二个tick(图中第二个步骤,即“下次更新循环”):
同步任务执行完毕,开始执行异步watcher队列的任务,更新DOM。Vue在内部尝试对异步队列使用原生的Promise.then和MessageChannel方法,如果执行环境不支持,会采用setTimeout(fn, 0)代替。

第三个tick(图中的第三个步骤)
在下次DOM更新循环结束之后,通过Vue.nextTick获取到改变后的DOM。通过setTimeout(fn, 0)也可以获取到。

异步是单独的一个tick,不会和同步发生在一个tick里,这也是DOM不会马上改变的原因。

参考链接:Vue.nextTick的原理和用途

猜你喜欢

转载自blog.csdn.net/weixin_45832482/article/details/123541993