如何在Vue中使用 nextTick()
Vue组件的数据(道具或状态)的变化不会立即反映在DOM中。相反,Vue会异步更新DOM。
你可以使用Vue.nextTick() 或vm.$nextTick() 函数来捕捉Vue更新DOM的时刻。让我们详细看看这些函数是如何工作的。
1.Vue.nextTick()
当改变Vue组件数据时,DOM会异步更新。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.show 是true ,那么this.$refs.content 是undefined :这意味着DOM与组件的数据不同步。
如果你想抓住DOM刚刚被更新的时刻,那么你需要使用一个特殊的函数Vue.nextTick(callback) 。它在新的数据更新到达DOM后立即执行callback 。
让我们找到<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>
打开演示,点击几次插入/移除按钮。你会看到this.$refs.content (包含<div> 元素的引用)是undefined ,或者包含一个元素--与this.show 的值完全对应。
同时,Vue.nextTick(callback) ,当所有的子组件更新都提交给DOM时,就会执行callback 。
2. this.$nextTick()
Vue允许在组件实例上使用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() 如果你想访问当前组件实例的更新,使用NextTick()更方便。
3. nextTick() with async/await
如果Vue.nextTick() 或this.$nextTick() 被调用而没有参数,那么这些函数就会返回一个承诺,当组件数据变化到达DOM时就会被解决。
这有助于利用更可读的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。最后, console.log(this.$refs.content)记录引用的实际内容。
我的建议是使用this.$nextTick() 与async/await 语法,因为它比回调的方法更容易阅读。
4.总结
当你改变组件的数据时,Vue会异步地更新DOM。
如果你想在组件数据改变后捕捉到DOM被更新的时刻,那么你需要使用Vue.nextTick(callback) 或this.$nextTick(callback) 函数。
它们的单个callback 参数将在DOM更新后立即被调用:并且你可以保证获得与组件数据同步的最新DOM。
另外,如果你不提供回调参数给Vue.nextTick() 或this.$nextTick(): 那么这些函数将返回一个正在解决DOM更新时的承诺。
使用这样的async/await 语法使代码比回调的方法更易读。