NextTick 是什么? 它在 Vue.js 中做什么?

我读了 那些文件,但还是看不懂。

我知道 datacomputedwatchmethods做什么,但是 nextTick()在 Vue.js 中用来做什么?

176581 次浏览

Next Tick 基本上允许您在对反应属性(数据)进行一些更改之后,在值重新呈现组件之后运行一些代码。

// modify data
vm.msg = 'Hello'
// DOM not updated yet
Vue.nextTick(function () {
// this function is called when vue has re-rendered the component.
})
    

// usage as a promise (2.1.0+, see note below)
Vue.nextTick()
.then(function () {
// this function is called when vue has re-rendered the component.
})

来自 Vue.js 文档:

推迟在下一个 DOM 更新周期之后执行的回调。在更改了一些数据后立即使用它,以等待 DOM 更新。

了解更多,给你

时机很重要

nextTick 允许你执行代码 之后你已经修改了一些数据,Vue.js 已经根据你的数据修改更新了虚拟 DOM,但是 之前浏览器已经在页面上做了修改。

通常情况下,开发人员使用本地 JavaScript 函数 setTimeout实现类似的行为,但使用 setTimeout将控制权交给浏览器 之前,它将控制权交还给您(通过调用您的回调)。

例子

假设您更改了一些数据; 然后 Vue 根据该数据更改更新 vDOM (这些更改尚未由浏览器呈现到屏幕上)。

如果您此时使用 nextTick,您的回调将立即被调用,并且浏览器将在该回调完成执行后更新页面。

如果您使用的是 setTimeout,那么浏览器将有机会更新页面,而且 那么会调用您的回调函数。

您可以通过创建如下所示的小组件来可视化这种行为:
(检查 这把小提琴看它的生活)

<template>
<div class="hello">
\{\{ msg }}
</div>
</template>


<script>
export default {
name: 'HelloWorld',
data() {
return {
msg: 'One'
}
},
mounted() {
this.msg = 'Two';


this.$nextTick(() => {
this.msg = 'Three';
});
}
}
</script>

运行本地服务器。您将看到显示的消息“ Three”。

现在,用 setTimeout代替 this.$nextTick:

setTimeout(() => {
this.msg = 'Three';
}, 0);

重新加载浏览器。在看到“三”之前,您将看到“二”。

这是因为,对于 setTimeout:

  1. Vue 将 vDOM 更新为“ Two”
  2. Vue 给了浏览器控制权
  3. 浏览器显示“2”
  4. 复试已经召开了
  5. Vue 将 vDOM 更新为“三”
  6. Vue 给了浏览器控制权
  7. 浏览器显示“三”

但是使用 nextTick,我们跳过了步骤2和步骤3!Vue 没有在第一次 vDOM 更新后传递控制权,而是调用回调 马上,这将阻止浏览器在回调完成之前进行更新。在本例中,这意味着“ Two”实际上从未显示。

要理解 Vue 如何实现这一点,您需要理解 JavaScript事件循环微任务的概念。

一旦你清楚了这些概念,检查 NextTick 的源代码

为了使 Pranshat 关于使用 nextTicksetTimeout的区别的回答更加明确,我分叉了他的小提琴: 给你

mounted() {
this.one = "One";
     

setTimeout(() => {
this.two = "Two"
}, 0);
      

//this.$nextTick(()=>{
//  this.two = "Two"
//})}
}

您可以看到,在使用 setTimeOut时,一旦组件挂载,初始数据就会非常短暂地闪烁,然后再进行修改。然而,在使用 nextTick时,数据在呈现给浏览器之前被劫持、更改。所以,浏览器显示的数据更新,甚至没有任何旧的知识。 希望能一下子把这两个概念说清楚。

我已经创建了一个有用的演示,在 Vuejs 我们可以使用 nextTick 的场景,如果你想在你的 DOM 更新后立即更新或运行一些东西,请参阅 addMessage 函数,其中我正在调用另一个函数,其中我使用 nextTick 函数来更新滚动条以查看最新消息。

<!DOCTYPE html>
<html>
<head>
<title>CDN VUE 3</title>
</head>
<body>
<div id="app">
<div ref="scrolledList" style="height: 100px; width: 150px; border:1px solid red; overflow: auto; margin-bottom: 15px; padding: 5px;">
<ul ref="scrolledHeight" style="margin: 0; padding: 0;">
<li v-for="msg in messages">
\{\{msg}}
</li>
</ul>
</div>
<input type="text" placeholder="Add Message" v-model="message" />
<button @click="addMessage" @keyup.enter="addMessage"> Add Message</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message: '',
messages: [1,2,3,4,5,6,7,8,9,10]
}
},
mounted() {
this.updateScrollNextTick()
},
methods: {
addMessage() {
if(this.message == ''){
return
}
this.messages.push(this.message)
this.message = ""
this.updateScrollNextTick()
},
updateScrollNextTick () {
this.$nextTick( () => {
let scrolledHeight = this.$refs.scrolledHeight.clientHeight
this.$refs.scrolledList.scrollTo({
behavior: 'smooth',
top: scrolledHeight
})
})
}
},
})
.mount("#app")
</script>
</body>
</html>

1-NextTick ()出现在页面的第一次渲染,以及其他所有渲染 之后重新渲染。 OnUpdate ()不会调用第一次渲染,但 之后的每次重新渲染(每次更新)。

2-NextTick ()出现在 OnUpdate ()之前,也出现在 OnUpdate ()之前 OnForeUpdate ()