前言
毕业一年,前端小白到技术大牛长路漫漫,写博客做总结真的是学习的一个好方法,在前端的路上,让我们一起成长进步,早日进大厂,实现自己事业的一片蓝天。
今天这篇文章讲一讲vue.nextTick()那些事,希望看到这篇文章的伙伴可以从中受益。
一、nextTick()是什么?
vue实现响应式并不是数据一发生变化就立即更新dom,而是按照一定的策略异步更新dom。下面附上vue官方文档的解释:
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的
Promise.then
和MessageChannel
,如果执行环境不支持,会采用setTimeout(fn, 0)
代替。
例如,当你设置
vm.someData = 'new value'
,该组件不会立即更新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在DOM状态更新后做点什么,这就可能有些棘手。虽然Vue.js通常鼓舞开发人员沿着“数据驱动”的方式思考,避免直接操作DOM,但是有时候我们确实需要这么做。为了在数据变化后等待Vue完成更新DOM,可以在数据变化之后立即使用Vue.nextTick(callback)
。这样回调函数会在DOM更新之后调用。
举一个栗子:
<template>
<div id="app">
<div ref="ref1">This is {{msg1}}</div>
<div ref="ref2">This is {{msg2}}</div>
<button @click="update">update</button>
</div>
</template>
<script>
new Vue({
el:"#app",
data: {
msg1: 'oldValue1',
msg2: 'oldValue2'
},
methods: {
update() {
this.msg1 = "newValue1";
this.msg2 = "newValue2";
console.log(this.$refs.ref1.innerText);
this.nextTick(() => {
console.log(this.$refs.ref2.innerText);
})
},
}
})
</script>
//This is oldValue1
//This is newValue2
可以看到,msg1显示的内容还是之前的,但是msg2显示的内容是更新之后的。
二、nextTick()使用场景和原因
1.created()钩子函数
在Vue生命周期的created()钩子函数中进行DOM操作一定要放在Vue.nextTick()的回调函数中。
原因: created()阶段已经完成:数据观测,属性和方法的运算,watch/event事件回调。然而挂载阶段还未开始,$el属性还不可见。所以DOM还未进行任何渲染,如果此时操作DOM无异于徒劳,所以如果要在created()里面操作DOM一定要放在Vue.nextTick()回调函数中执行。在mounted()钩子函数中,DOM已经完成挂载和渲染,所以此时操作DOM不会出现任何问题。
created() {
this.nextTick(() => { //不使用Vue.nextTick()会报错
this.$refs.ref1.innerText="created中更改了内容";
})
}
2.数据变化之后,你想立即使用js操作新的视图做点什么的时候
代码如下(示例):
<template>
<div id="app">
<div ref="ref1">This is {{msg1}}</div>
<div ref="ref2">This is {{msg2}}</div>
<button @click="update">update</button>
</div>
</template>
<script>
new Vue({
el:"#app",
data: {
msg1: 'oldValue1',
msg2: 'oldValue2'
},
methods: {
update() {
this.msg1 = "newValue1";
this.msg2 = "newValue2";
console.log(this.$refs.ref1.innerText);
this.nextTick(() => {
console.log(this.$refs.ref2.innerText);
})
},
}
})
</script>
//This is oldValue1
//This is newValue2
总结
Vue的dom更新是异步的。在数据改变之后,视图会在DOM下一次更新之后才会获得相应更新。如果要基于新试图做点什么的话,要放在Vue.nextTick()回调函数中执行。