Vue 在更新 DOM 時是異步執行的。
只要偵聽到數據變化,Vue 將開啟一個隊列,並緩沖在同一事件循環中發生的所有數據變更。如果同一個 watcher 被多次觸發,只會被推入到隊列中一次。這種在緩沖時去除重復數據對於避免不必要的計算和 DOM 操作是非常重要的。
異步更新DOM實例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue nextTick</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<example></example>
</div>
<script>
// 注冊 example 組件
Vue.component('example', {
template: '<span ref="box" @click="updateMessage">{{ message }}</span>',
data () {
return {
message: '未更新'
}
},
methods: {
updateMessage () {
this.message = '已更新'
console.log('nextTick方法前--->', this.$refs.box.textContent) // => '未更新'
this.$nextTick(function () {
console.log('nextTick方法內--->', this.$refs.box.textContent) // => '已更新'
})
console.log('nextTick方法后--->', this.$refs.box.textContent) // => '未更新'
}
}
})
// 創建根實例
new Vue({
el: '#app'
})
</script>
</body>
</html>
點擊 span , 執行 updateMessage方法,輸出結果如下:
nextTick方法前---> 未更新
nextTick方法后---> 未更新
nextTick方法內---> 已更新
可見,Vue 數據發生變化之后,視圖不會立即變化。該更新過程是異步的。
所以,如果要獲取更新后的視圖,可以使用 $nextTick(callback)。這里的回調函數(callback)將在數據更新完成,視圖更新完畢之后被調用。
$nextTick 結合 async/await 語法
$nextTick() 返回一個 Promise 對象,所以可以使用新的 ES2016 async/await 語法完成相同的事情:
methods: {
async updateMessage () {
this.message = '已更新'
console.log('nextTick方法前--->', this.$refs.box.textContent) // => '未更新'
await this.$nextTick(function () {
console.log('nextTick方法內--->', this.$refs.box.textContent) // => '已更新'
})
console.log('nextTick方法后--->', this.$refs.box.textContent) // => '已更新'
}
}
執行點擊事件,打印結果:
nextTick方法前---> 未更新
nextTick方法內---> 已更新
nextTick方法后---> 已更新
$nextTick 常用場景
在Vue生命周期鈎子函數created()
中進行的DOM操作。
由於created()鈎子函數中還未對DOM進行任何渲染,所以無法直接操作,需要通過$nextTick()回調來完成。
created() {
console.log(this.$refs.box.textContent); // TypeError: Cannot read property 'textContent' of undefined
this.$nextTick(() => {
console.log(this.$refs.box.textContent); // 未更新
})
},