- 以前只知道nextTick()是怎么用的,但是对于其原理还是不太清楚
- 现在查了查官方的文档,算是弄明白了
1、Vue中的DOM更新机制
-
Vue异步执行DOM更新。只要观察到数据变化,Vue将开启一个异步队列,然后将这些变化先放在一个异步的队列中,同时vue还会对这个队列里面的操作进行去重,比如你修改了这个数据三次,它便只会保留最后一次
-
vue把DOM更新放在异步队列会产尝试使用promise.then、MutationObserver和setImmediate(如果环境不支持如IE,才会采用setTimeout(fn,0)代替,但是IE现在已经无了,所以不用担心这一点)
-
当Vue把DOM的更新放在异步队列(微任务队列)中,会出现以下几点情况:如果我们在同步执行栈中修改了数据,这时候会将dom的更新放在异步队列中,接着我们若是想继续在同步执行栈中获取dom便不能获取到更新后的dom(异步队列中的任务要等同步执行栈执行完毕后才会开始执行)
-
此时解决的办法便是nextTick
2、vue.$nextTick()
-
$ nextTick():放在$nextTick()中的操作不会立即执行,而是等数据更新,DOM更新完成之后才会执行,这样拿到的DOM肯定就是最新的
-
也就是说$nextTick会将里里面的回调函数放到微任务队列中(环境不支持时,放到宏任务队列),以延迟它的执行顺序
-
用法如下
<div id='root'>{{msg}}</div>
<script>
var vm = new Vue({
el:'#root',
data:{
msg:'old msg'
}
}),
vm.msg = 'new msg'
vm.$el.textContent === 'new msg' //false
vm.$nextTick(function(){
vm.$el.textContent === 'new msg' //true
})
</script>
- $nextTick会返回一个Promie对象,所以使用async/await可以完成同样的事情
- 因为await要等到后面Promise对象的异步操作的状态改变之后,次啊会继续执行函数下面的代码
- 所以当$nextTick(callback)将里面的回调函数放入异步队列后,要等到异步队列中的回调函数执行完毕后,其返回的Promise对象的状态才会改变,这样就意味着DOM操作已经更新
methods:{
updataMsg: async function(){
this.msg = 'new msg'
this.$el.textContent === 'new msg' //false
await this.$nextTick()
this.$el.textContent === 'new msg' //true
}
}