Vue.js 中this.$nextTick()用法

定义

等待下一次 DOM 更新刷新的工具方法。

简单地说nextTick() 可以在当前代码块的同步代码执行完毕后,立即执行传入的回调函数。
通常情况下,Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新,这意味着如果你想在 DOM 更新后立即执行一些操作,可能会遇到问题。这时就可以使用 nextTick() 方法来确保回调函数在 DOM 更新后立即执行。

需要注意的是,nextTick() 方法是异步的,所以回调函数的执行顺序是不确定的。如果你需要确保回调函数在 Vue 实例更新后立即执行,并且需要控制回调函数的执行顺序,可以使用 Vue.nextTick().then() 方法。

理解nextTick()首先得从JS执行机制开始

JS执行机制

我们都知道 JS 是单线程语言,即指某一时间内只能干一件事
那为什么 JS 不能是多线程呢?多线程就能同一时间内干多件事情了

一个很简单的例子,如果同一时间,一个添加了 DOM,一个删除了 DOM, 这个时候语言就不知道是该添还是该删了,所以从应用场景来看 JS 只能是单线程

单线程就意味着我们所有的任务都需要排队,后面的任务必须等待前面的任务完成才能执行。如果前面的任务耗时很长,一些从用户角度上不需要等待的任务就会一直等待,这个从体验角度上来讲是不可接受的,所以JS中就出现了异步的概念

  • 同步 :在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
  • 异步 :不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行

运行机制

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

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

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

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

组件的生命周期

请添加图片描述

  • beforeCreate(): 是生命周期初始化的时候。 它在 Vue 引擎创建组件之前调用,并且尚未设置任何内容(事件、数据、属性等)。
  • created(): 在渲染 DOM 之前运行。在此阶段,可以访问数据和事件。
  • beforeMount(): 是编译模板和作用域样式的地方,尽管您仍然无法操作 DOM,并且实例vm.$el尚未创建。
  • mounted(): 可以使用和操作组件。这意味着你的组件属于 DOM。
  • beforeUpdate(): 在对组件进行更改之前,可以方便地实现逻辑
  • updated(): 允许您在组件发生更改后立即实现任何逻辑。
  • beforeUnmount() : 清理组件,不会留下任何可能导致应用内存泄漏的变量或事件。
  • unmounted(): 可用于在组件被销毁后清除间隔或脚本。

nextTick()应用

1、 当 Vue 组件数据发生变化时,DOM 会异步更新。Vue 从所有组件收集对虚拟 DOM 的多次更新,然后创建一个批次来更新 DOM。
在单个批次中更新 DOM 比进行多个小更新的性能更高。
当数据发生变化时,Vue 会将需要更新的组件放入更新队列中,并在下一个事件循环中进行批量更新。这样可以避免频繁的 DOM 操作,提高性能。

下面是一个简单的例子来演示这个机制:

<div id="app">
  <p>{{ message }}</p>
  <button @click="changeMessage">Change Message</button>
</div>
new Vue({
  el: "#app",
  data: {
    message: "Hello Vue!"
  },
  methods: {
    changeMessage() {
      this.message = "Updated Message";
      console.log("Message changed");
    }
  }
});

在上述例子中,当点击按钮时,changeMessage 方法会将 message 的值修改为 “Updated Message”。同时,在控制台中输出 “Message changed”。

由于 Vue 的批量更新机制,当点击按钮时,实际的 DOM 更新会在下一个事件循环中进行。这意味着控制台中的输出会先执行,而实际的 DOM 更新稍后进行。

这种批量更新的机制可以减少不必要的 DOM 操作,提高性能和响应速度。

2、 当我们可以使用 settimeout 时,可以使用nextTick。

Vue 异步更新 DOM。因此,当您对 DOM 进行更改时,它不会立即发生。 它首先检查是否有任何其他状态更改。只有这样您才能在浏览器上看到呈现的更改!
这一切发生得如此之快,你甚至都没有看到。 那么,为什么它很重要?

这确实很重要,如果您需要在进行更改后立即运行一个函数。这是你需要用来nextTick()等待 DOM 更新的地方。

这就是为什么在某些时候你必须使用setTimeout(),因为你必须给浏览器一些时间来更新 DOM。否则,你的函数没有被执行。

但setTimeout()有其后备方案。它将在nextTick(DOM更新)之后执行回调,同时nextTick()优先执行回调函数!setTimeout()延迟您的回调,因为它首先必须通过使用它来将控制权交给浏览器,然后只有在调用您的回调函数时才返回给您。
举个例子:

<template>
  <h1>{{ message }}</h1>
</template>

<script>
  export default {
    data() {
      return {
        message: "Joey doesn’t share food!",
      };
    },
    mounted() {
      console.log(this.message);
      this.message =
        "Well, maybe I don't need your money. Wait, wait, I said maybe!";
      console.log(this.message);
      setTimeout(() => {
        this.message = "Hi, I’m Chandler. I make jokes when I’m uncomfortable.";
      console.log(this.message);
      }, 300);
      this.$nextTick(() => {
        this.message =
          "It's a moo point. It's like a cow's opinion; it doesn't matter. It's moo.";
        console.log(this.message);
      });
    },
  };
</script>

结果如下:
在这里插入图片描述
可以看见next Tick在setTimeout之前运行,这就是nextTick性能高的原因

那为什么不用来watch()监听变化呢?简而言之,watch()用于在组件数据更改时执行某些操作,而nextTick()用于在应用程序更新后执行代码

3、回调函数作为第一个参数

mounted () {
  this.$nextTick(() => {
    this.message = 'Call me maybe!';
    console.log(this.message);
  });
}

在上述代码中,mounted() 会在组件挂载到 DOM 后被调用。

在这个例子中,我们将 message 的值修改为 “Call me maybe!”,然后在控制台中打印出 message 的值。

使用 this.$nextTick() 方法可以确保在 DOM 更新后执行回调函数。这是因为 Vue 在更新 DOM 后会异步执行回调函数,所以如果我们直接在 mounted() 中修改 message 的值并打印,可能会得到旧的值。通过使用 this.$nextTick(),我们可以确保回调函数在 DOM 更新后执行,从而得到正确的值。

当您想要执行某些操作并确保更新子组件的 props、数据或计算值时,回调会非常方便。您的代码会在下一个 DOM 更新周期运行后以及浏览器呈现该更改后延迟。

换句话说,回调被推迟到下一个 DOM 更新周期之后执行。

4、this.$nextTick().then()

mounted () {
  this.$nextTick().then(() => {
    this.message = 'You promised!';
    console.log(this.message);
  });
}

使用 this.$nextTick().then() 的方式可以确保回调函数在 DOM 更新后执行。由于 this.$nextTick() 返回一个 Promise 对象,我们可以使用 .then() 方法来注册回调函数,并在 Promise 被解析时执行这个回调函数。
5、async 与 this.$nextTick()

async mounted () {
  await this.$nextTick(() => {
    this.message = 'I will always wait for you!';
    console.log(this.message)
  });
}

在上述代码中,我们使用了 asyncawait 关键字来确保在 DOM 更新后执行一些操作。

mounted() 钩子函数中,我们使用 await 关键字来等待 this.$nextTick() 方法的执行。await 关键字可以暂停异步函数的执行,直到 this.$nextTick() 返回的 Promise 对象被解析。

通过使用 asyncawait,我们可以将异步代码写成同步的形式,使得代码更加清晰和易读。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值