Vue.nextTick()
首先,我们了解一下Vue的响应式原理,当你把一个普通的 JavaScript 对象传入 Vue 实例作为data选项,Vue 将遍历此对象所有的 property,并使用Object.defineProperty把这些 property 全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。
1、举个例子
<template> <div> <div ref="msgDiv">{{msg}}</div> <div v-if="msg1">msg1的值:{{msg1}}</div> <div v-if="msg2">msg2的值(有nextTick):{{msg2}}</div> <div v-if="msg3">msg3的值(区别msg1):{{msg3}}</div> <button @click=handleClick></button> </div> </template> <script> export default { name: 'Hello', data () { return { msg: '原始值', msg1: '', msg2: '', msg3: '' } }, methods: { handleClick () { this.msg = '修改后的值' this.msg1 = this.$refs.msgDiv.innerHTML this.$nextTick(() => { this.msg2 = this.$refs.msgDiv.innerHTML }) this.msg3 = this.$refs.msgDiv.innerHTML } } } </script> <style lang="scss" scoped> </style>
点击之后的效果:
从图中可以得知:msg1和msg3显示的内容还是变换之前的,而msg2显示的内容是变换之后的。
2、this.$nextTick()的应用场景
- 在Vue生命周期的
created()
钩子函数进行的DOM操作一定要放在Vue.nextTick()
的回调函数中。在created()
钩子函数执行的时候,DOM其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()
的回调函数中。与之对应的就是mounted()
钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
- 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进
Vue.nextTick()
的回调函数中。
3、async/await的形式
async handleClick () { this.msg = '修改后的值' this.msg1 = this.$refs.msgDiv.innerHTML await this.$nextTick() this.msg2 = this.$refs.msgDiv.innerHTML this.msg3 = this.$refs.msgDiv.innerHTML }