一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情
对Vue组件数据(props或state)的更改并不会立即在DOM中渲染。因为,Vue异步更新DOM。
我们可以通过使用Vue.nextTick() 或 vm.$nextTick()函数抓住Vue更新DOM的那一刻。让我们详细了解一下这些函数是如何工作的。
1.Vue.nextTick()
Vue从所有组件收集多个虚拟DOM的更新,然后尝试一次性全部更新DOM。例如,让我们看看一个可以切换一个元素的显示与否的组件:
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>
<script>
export default {
data() {
return {
show: true,
};
},
methods: {
handleClick() {
this.show = !this.show;
console.log(this.show, this.$refs.content);
},
},
};
</script>
单击“插入/删除”按钮可更改this.show数据,这里使用v-if=“show”指令切换 <div id=“content”>元素的显示与否。
在handleClick内部,控制台中打印的this.show与打印到控制台的this.refs.content 的值为 undefined(实际上他正确的值应该是( <div data-v-665bb11f="">I am an element</div>):这意味着DOM的渲染与组件的数据是不同步的。
如果你想抓住DOM更新的那一刻,那么你需要使用一个特殊的函数Vue.nextTick(callback)。它在DOM渲染新数据后立即执行回调。
可以让我们找出<div>元素从DOM中插入或移除的时刻:
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>
<script>
import Vue from "vue";
export default {
data() {
return {
show: true,
};
},
methods: {
handleClick() {
this.show = !this.show;
Vue.nextTick(() => {
console.log(this.show, this.$refs.content);
});
},
},
};
</script>
试试这个demo
打开demo并单击几次“插入/删除”按钮。你会看到这个this.$refs.content (包含<div>元素的引用)和this.show 是完全同步的。
2.this.$nextTick()
也可以在组件实例上的使用this.$nextTick(callback)。
在下面的示例中,handleClick()方法更改了this.show 数据,this.$nextTick()捕捉到了dom更新数据的那一刻。:
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>
<script>
export default {
data() {
return {
show: true,
};
},
methods: {
handleClick() {
this.show = !this.show;
this.$nextTick(() => {
console.log(this.show, this.$refs.content);
});
},
},
};
</script>
this.$nextTick()使用起来更加的方便。
3.nextTick() with async/await
如果Vue.nextTick() 或 this.$nextTick()调用时不带参数,函数将会返回一个promise,在组件数据DOM更新后得到resolved。
这使得我们可以使用可读性更强的async/await语法。
例如,我们通过使用async/await语法捕获DOM更新,使前面的代码更具可读性:
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>
<script>
export default {
data() {
return {
show: true,
};
},
methods: {
async handleClick() {
this.show = !this.show;
await this.$nextTick();
console.log(this.show, this.$refs.content);
},
},
};
</script>
async handleClick(已标记为异步函数。)
当单击“插入/删除”按钮时,this.show 的值会发生变化。
await this.$nextTick() 会等待DOM更新。最后是控制台打印(this.nextTick(),因为它比回调方法更具可读性。
4.总结
更改组件的数据时,Vue会异步更新DOM。
如果希望捕捉组件DOM更新后的那一刻,则需要使用Vue.nextTick(callback)或this.$nextTick(callback)函数。
它们的单个回调函数参数将在DOM更新之后立即调用:并且我们将获得与组件数据同步的最新DOM。
或者,如果不传递回调函数作为参数给Vue.nextTick() 或 `this.$nextTick():函数将返回一个promise,该promise将在DOM更新时resolved。
使用async/await语法会使代码比回调方法更具可读性。