Vue-查缺补漏(5)-异步更新队列

一个例子,有一个div,默认用v-if将它隐藏,点击一个按钮后,改变v-if的值,使div显现,同时获取div的文本内容

1
2
<div ref="div" v-if="showDiv">隐藏div内容</div>
<button @click="getText">获取文本内容</button>
1
2
3
4
5
6
7
methods: {
getText: function() {
this.showDiv = true;
let text = this.$refs.div.innerHTML;
alert(text);
}
}

运行后出错:Cannot read property 'innerHTML' of undefined,获取不到div元素。
此涉及到 Vue 的一个重要概念:异步更新队列

异步更新队列

Vue 在观察到数据变化并不会直接更新 DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据变化。并在缓冲时去重重复数据,从而避免不必要的计算和 DOM 操作。如果同一个watcher被多次触发,只会被推入队列中一次。
然后,在下一个事件循环tick中,Vue 刷新队列并执行实际(已去重的)工作。
所以,在设置this.showDiv = true后,改组件不会立即被渲染,当刷新队列时,组件会在下一个tick更新渲染。
为了在数据变化之后等待Vue 完成更新 DOM,可以在数据变化后立即使用vm.$nextTick(callBack),这样回调函数在 DOM 更新后就会被调用了。
回调函数中的this将自动绑定到调用它的 Vue 实例上

1
2
3
4
5
6
7
8
9
methods: {
getText: function() {
this.showDiv = true;
this.$nextTick(function() {
let text = this.$refs.div.innerHTML;
alert(text);
});
}
}

因为$nextTick()返回一个Promise对象,所以可以使用新的ES2016 async/await 语法来 实现

1
2
3
4
5
6
7
8
methods: {
getText: async function() {
this.showDiv = true;
await this.#nextTick();
let text = this.$refs.div.innerHTML;
alert(text);
}
}