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); // 未更新
})
},