在 Vue 中,当 data 数据发生改变时,Vue 会自动触发重新渲染视图的过程。但是,有时候我们会发现data数据改变了,但真实 DOM 并没有及时更新。为什么?
Vue 官方文档对其的定义:
我们可以理解成, Vue 在更新 DOM 时是异步执行的。
正是这样,因为 Vue 的响应式系统采用了异步更新队列的机制,当我们修改 data 中的数据后, Vue 并不会立即更新真实 DOM ,而是把这个更新操作放入一个队列,其他数据的变化操作也放入这个队列,视图需要等到队列中所有数据变化完成之后,统一进行批量更新
在大多数情况下,Vue会自动在数据变化时执行 DOM 更新,因此很少需要手动使用 $nextTick() 方法。但是,在一些特定场景下,如果需要确保在 DOM 更新后执行某些操作, $nextTick() 方法是非常有用的。
那么它的使用场景是什么呢?
1、若需要在组件中修改 data 数据之后,立即操作更新后的 DOM 元素 或 使用 $refs 获取到 DOM 元素
<template>
<div>
<div class="hello">
<p ref="g_name">
当前姓名:<b>{{ name }}</b>
</p>
<p class="sex">{{ sex }}</p>
<button @click="changeName">改变名称</button>
<button @click="changeSex">改变性别</button>
</div>
</div>
</template>
<script>
export default {
name: "DemoPages",
data() {
return {
name: "张三",
sex: '男'
};
},
methods: {
changeName() {
this.name = "李四";
//建议以箭头函数的形式传入回调函数,this自动绑定外层作用域的 this(当前组件实例),不会受到其他因素的影响。
this.$nextTick(() => {
console.log(this.$refs["g_name"].innerHTML); // 当前姓名:<b>李四</b>
})
},
changeSex() {
this.sex = '女';
this.$nextTick(() => {
const element = document.querySelector('.sex');
console.log(element.innerHTML);// 女
//操作更新后的DOM的内容
//...
})
}
}
};
</script>
<style scoped>
</style>
上述代码中的 changeName 方法中若不用 nextTick ,则拿到的真实 DOM 节点的打印还是
当前姓名:<b>张三</b>
如果你需要在 this.$nextTick 中获取回调函数的返回值,你可以使用 Promise 进行封装。
//如果需要在$nextTick()中获取回调函数的返回值,你可以使用Promise进行封装
const promise = new Promise((resolve) => {
this.$nextTick(() => {
// 在DOM更新后执行的操作
console.log("DOM已更新");
// 获取更新后的DOM元素
console.log(this.$refs["g_name"].innerHTML); // 当前姓名:<b>李四</b>
// 返回结果
resolve(this.name)
})
})
promise.then((result) => {
console.log("回调函数的返回值为:", result) // 当前姓名:<b>李四</b>
})
需要注意的是,需要在 created 和 mounted 里需要操作渲染后的视图,也最好将处理内容传入 nextTick 的回调函数(callback)中
在 created 钩子函数中,组件实例已经创建完成,但是 DOM 还未渲染,因此在这个阶段进行一些需要操作 DOM 元素的操作,可能无法获取到正确的结果。例如,如果需要获取某个 DOM 元素的尺寸或者修改样式,由于 DOM 还未渲染,无法获取到正确的值或者修改无效。
在 mounted 钩子函数中,组件已经被挂载到 DOM 上,此时可以获取到正确的 DOM 元素并进行操作。然而,由于 Vue 会在 mounted 钩子函数中进行异步的 DOM 更新操作,这些操作是由 Vue 引擎处理的,无法立即得到结果。因此,如果在 mounted 钩子函数中直接进行 DOM 操作,可能会存在一定的延迟。
综上所述, this.$nextTick 方法在 created 和 mounted 钩子函数中的使用,主要是为了在正确的时机进行 DOM 操作,避免可能出现的延迟或无效操作。
2、在更新后执行其他异步操作:当需要在更新后执行其他异步操作时,需要将这些操作放在 this.$nextTick 的回调函数中。例如,发送网络请求、操作浏览器缓存等。
// 发送网络请求
this.$nextTick(() => {
axios.get('/api/data').then(res => {
console.log(res.data);
});
});
// 操作浏览器缓存
this.$nextTick(() => {
localStorage.setItem('myData', 'Hello, World!');
});
Ps:Vue.nextTick 是全局方法,可以在任何地方直接调用;this.$nextTick 是 Vue 实例的方法,它是通过 Vue 的原型链绑定到每个 Vue 实例上的,可以在 Vue 组件中使用。
两者的作用和使用方式完全一样,都是用于在下次 DOM 更新循环结束后执行回调函数。它们的使用场景和效果也是一样的。
但是在 Vue3 中, Vue.nextTick 方法已经被废弃,推荐使用 this.$nextTick 方法。在Vue2中, nextTick 方法仍然可用,但建议使用 this.$nextTick 以保持一致性