Vue--nextTick--作用/用法/原理

Vue的nextTick用于在DOM更新后执行回调,确保能获取到最新的DOM状态。它会在同一个事件循环的末尾执行,遵循浏览器的异步更新策略。例如,在修改数据后立即读取DOM会获取到旧值,而通过nextTick则能在DOM更新后获取新值。在组件的created生命周期钩子中,由于DOM未创建,直接访问$refs会为空,但使用nextTick则能在DOM创建后访问。Vue的异步更新队列确保了多次数据修改仅触发一次DOM更新,提高了效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文网址:Vue--nextTick--作用/用法/原理_IT利刃出鞘的博客-CSDN博客

简介

说明

        本文介绍Vue的nextTick的作用、用法、原理。

官网网址

https://v2.cn.vuejs.org/v2/api/#Vue-nextTick

作用

        Vue 在修改数据后,视图(DOM)不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以,在修改数据之后立马读取DOM是获取不到新数据的,获取到的是原来的DOM数据。

        使用nextTick可以获得DOM更新后的数据。在下次 DOM 更新之后Vue会回调nextTick指定的函数。可以在修改数据之后立即使用这个nextTick方法,在指定的函数里获取更新后的 DOM。

实例

1:修改数据后读取DOM

说明

        修改数据后立马读DOM是读不到的(读到的是旧数据),用nextTick才能读到。

代码

<template>
  <div class="outer">
    <div>
      这是CompA
    </div>
    <h3 ref="hello">{{ value1 }}</h3>
    <button @click="testClick()">测试一下</button>
  </div>
</template>

<script>

export default {
  name: 'CompA',
  data () {
    return {
      value1: 'aa'
    }
  },
  methods: {
    testClick () {
      this.value1 = 'bb'
      console.log('直接获取:' + this.$refs.hello.innerText)
      this.$nextTick(() => {
        console.log('nextTick获取:' + this.$refs.hello.innerText)
      })
    }
  }
}
</script>

<style scoped>
.outer {
  margin: 20px;
  border: 2px solid blue;
  padding: 20px;
}
</style>

测试

可以发现,直接读取值读到的是旧值,用nextTick获取到的是新值。

2:created获取DOM

说明

        我们知道,created被回调时,DOM还没有创建,读不到DOM,可以使用nextTick。

代码

<template>
  <div class="outer">
    <div>
      这是CompA
    </div>
    <h3 ref="hello">{{ value1 }}</h3>
  </div>
</template>

<script>

export default {
  name: 'CompA',
  data () {
    return {
      value1: 'aa'
    }
  },

  created () {
    console.log('created进入:' + this.$refs.hello)
    this.$nextTick(() => {
      console.log('created的nextTick:' + this.$refs.hello)
    })
  },
  mounted () {
    console.log('mounted进入:' + this.$refs.hello)
    this.$nextTick(() => {
      console.log('mounted的nextTick:' + this.$refs.hello)
    })
  }
}
</script>

<style scoped>
.outer {
  margin: 20px;
  border: 2px solid blue;
  padding: 20px;
}
</style>

结果

可以发现,在created中获取不到DOM,但在created里使用nextTick可以获取到。

Vue异步执行原理

  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  2. 异步任务有了运行结果时在"任务队列"(task queue)中放置一个事件。
  3. "执行栈"中的所有同步任务执行完毕时,系统会读取"任务队列"。对应的异步任务结束等待状态,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。

第一个 tick(图例中第一个步骤,即'本次更新循环'):

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

第二个 tick(图例中第二个步骤,即'下次更新循环'):

  1. 同步任务执行完毕,开始执行异步 watcher 队列的任务,更新 DOM 。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel 方法,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。

第三个 tick(图例中第三个步骤):

  1. 此时就是文档所说的:“下次 DOM 更新循环结束之后”
  2. 此时通过 Vue.nextTick 获取到改变后的 DOM 。通过 setTimeout(fn, 0) 也可以同样获取到。

简单总结事件循环:

  1. 同步代码执行
  2. 查找异步队列,推入执行栈,执行Vue.nextTick[事件循环1]
  3. 查找异步队列,推入执行栈,执行Vue.nextTick[事件循环2]...

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

在一个tick中多次更新数据页面只更新一次

即使在 Vue 中多么频繁地修改数据,最后 Vue 页面只会更新一次。

例如:

  1. 数据 name 被 页面引用,name 会收集到 页面的 watcher;
  2. name 被修改时,会通知所有收集到的 watcher 进行更新(watcher.update);
  3. 如果name 一时间被修改三次时,按道理应该会通知三次 watcher 更新,那么页面会更新三次,但是最后只会更新一次。

这是因为:

  1. 当数据变化后,把 watcher.update 函数存放进 nextTick 的 回调数组中,并且会做过滤。
  2. 通过 watcher.id 来判断 回调数组 中是否已经存在这个 watcher 的更新函数,不存在,才 push。
  3. 之后 nextTick时 遍历回调数组,便会执行更新。

        所以当三次修改数据的时候,会 push 回调数组 三个 watcher.update,但是只有第一次是 push 成功的,其他的会被过滤掉,因为已经存在了。

        不管你修改多少次数据,nextTick 的回调数组中只存在唯一一个 watcher.update,从而页面只会更新一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT利刃出鞘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值