$nextTick是如何工作的?与setTimeout的不同之处是什么?

目录
文章目录隐藏
  1. nextTick 做什么?
  2. setTimeout vs nextTick
  3. 何时使用 nexttick
  4. 总结

使用 Vue 已经有一段时间了,已经习惯了把$watch$emit写成实例方法。那么,$nextTick是用来做什么的?Vue 文档说,它”[defers]回调,在下一个 DOM 更新周期后执行”。

但是我并不相信。

接下来看看我是如何尝试这样做的:

this.loadingAnimation = true
this.startVeryLongCalculation()
this.completeVeryLongCalculation()
this.loadingAnimation = false

有用。 为什么?

nextTick 做什么?

nextTick接受一个延迟到下一个 DOM 更新周期的回调函数。这只是 Vue 的一种说法,”嘿,如果你想在 DOM 更新后执行一个函数(这种情况很少发生),我希望你使用nextTick而不是setTimeout“。

Vue.nextTick(() => {}) // syntax

下面很快就会讲到setTimeoutnextTick参数。我们用这个例子来可视化nextTick的行为:

<template>
  <div>
    {{ currentTime }}
  </div>
</template>

<script>
export default {
  name: 'getCurrentTime',
  data() {
    return {
      currentTime: ''
    }
  },
  mounted() {
    this.currentTime = 3;

    this.$nextTick(() => {
        let date = new Date()
        this.currentTime = date.getFullYear()
    });
  }
}
</script>

在 J 电脑上运行这个代码片段。它将显示2021年。并不是说如果你去掉nextTick,就不会得到同样的结果。然而,你应该明白,Vue 会根据数据中的内容对 DOM 进行修改。

在上面的代码片段中,Vue 将 DOM 更新为3,然后调用回调,将 DOM 更新为2021,最后将控制权交给浏览器,浏览器将显示2021

到目前为止,我们已经研究了 nextTick 在回调队列中插入回调函数并在适当的时候执行该函数。

这个你可能会感兴趣,nextTick中的回调是作为事件循环中的一个微任务使用的。nextTick源代码明确指出,”nextTick行为利用了微任务队列,可以通过本地的Promise.thenMutationObserver来访问。”

setTimeout vs nextTick

在 DOM 更新后执行函数的另一种方法是使用 JavaScript 的setTimeout()函数。

我们将上面的代码用setTimeout替换nextTick:

<template>
  <div>
    {{ currentTime }}
  </div>
</template>

<script>
export default {
  name: 'getCurrentTime',
  data() {
    return {
      currentTime: ''
    }
  },
  mounted() {
    this.currentTime = 3;

    setTimeout(() => {
      let date = new Date()
      this.currentTime = date.getFullYear()
    }, 0);
  }
}
</script>

运行此代码片段。 首先看到3然后2021。它发生得很快,因此如果没有看到此行为,需要刷新浏览器。

在上面的代码片段中,Vue 将 DOM 更新为3,并提供浏览器控制。然后浏览器显示3,调用回调函数,将 DOM 更新到2021,最后将控制权交给浏览器,现在浏览器显示2021

nextTick的实现在不支持PromiseMutationObserver的浏览器(IE 6-10 和 Opera Mini 浏览器)上,使用 setTimeout作为后备方法,对于不支持PromiseMutationObserver的浏览器(IE 10),它更倾向于setImmediate

何时使用 nexttick

  • 当你想使用setTimeout
  • 当你想确定 DOM 能反映你的数据时
  • 在尝试执行异步操作时,遇到Uncaught (in promise) DOMException等错误。记住,Vue 是异步更新 DOM 的

最后来个示例:

<div id="app">
  <div ref="listScroll" class="scrolledList">
    <ul ref="scrolledHeight">
      <li v-for="month in months">
        {{month}}
      </li>               
    </ul>
  </div>

  <input type="text" placeholder="Add Month" v-model="month">
  <button @click="addMessage" @keyup.enter="addMessage"> Add Month</button>
</div>

<script src="https://unpkg.com/vue@next"> 
  Vue.createApp({
    data() {
      return {
        month: '',
        months: ['Jan', 'Feb', 'Apr', 'May', 'June', 'July', 'Aug']
      }
    },
    mounted() {
      this.updateScrollNextTick()
    },
    methods: {
      addMessage() {
        if(this.month == ''){
          return
        }

        this.months.push(this.month)
        this.month = ''
        this.updateScrollNextTick()
      },
      updateScrollNextTick () {
        let scrolledHeight = this.$refs.scrolledHeight.clientHeight

        this.$nextTick(() => {
          this.$refs.listScroll.scrollTo({
            behavior: 'smooth',
            top: scrolledHeight
          })
        })
      }
    },
  })
  .mount("#app")
</script>

示例地址:点击这里

主要部分:

$nextTick 与 setTimeout 的使用对比

运行结果:

$nextTick 与 setTimeout 的使用对比

在上面的代码片断中,我们想在一个新项目被添加到列表中时获得平滑的向下滚动效果。浏览一下代码,尝试修改一下,去掉$nextTick,你就会失去那种平滑的滚动效果。你也可以尝试用setTimeout来代替nextTick

总结

在本文中,我们探索了$nextTick是如何工作的。我们进一步了解了它与普通的setTimeout的不同之处,并介绍了实际的用例。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » $nextTick是如何工作的?与setTimeout的不同之处是什么?

发表回复