$nextTick 与 setTimeout 的一点对比
nextTick做什么?
nextTick接受一个延迟到下一个DOM更新周期的回调函数。这只是Vue的一种说法,"嘿,如果你想在DOM更新后执行一个函数(这种情况很少发生),我希望你使用nextTick而不是setTimeout"。
Vue.nextTick(() => {}) // syntax
下面很快就会讲到setTimeout和nextTick参数。我们用这个例子来可视化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.then或MutationObserver来访问。"
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的实现在不支持Promise和MutationObserver的浏览器(IE 6-10和Opera Mini浏览器)上,使用setTimeout作为后备方法,对于不支持Promise和MutationObserver的浏览器(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。 文章摘自:www.toutiao.com/a6984566176…