携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天 [携手创作,共同成长]
this.$nextTick()
首先在深入学习this.nexTick之前我们要去了解一个概念,就是vue的dom更新他是异步的,并不是数据发生改变之后dom就立即改变,而是等同一事件循环中的所有数据变化完成之后,在统一进行视图的更新。
1、this.$nextTick()使用的场景:
created阶段的dom是没有生成渲染的,这个时候我们要在这个生命周期里面获取dom的话,就可以使用nextTick方法就获取
mounted阶段,如果需要操作渲染后的视图,要使用nextTick方法,因为在mounted钩子里面不会承诺其子组件也挂载完毕
2、this.$nextTick()原理及其使用
官方给的解释是:
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
还是很难理解的,这里通过代码的实例带你去领略:
<template>
<div>
<p ref="testDom">{{name}}</p>
<button @click="change">改变</button>
</div>
</template>
<script>
export default {
data() {
return {
name:'前端同学'
}
},
created() {
},
methods: {
change(){
this.name='我是测试同学'
console.log(this.$refs.testDom.innerHTML);
this.$nextTick(()=>{
console.log(this.$refs.testDom.innerHTML);
})
}
},
}
</script>
好的这就是我们整个的一个代码,逻辑也很简单,就是点击按钮去改变name值,让其在页面上展示出来,再点击改变的这个事件里面有两个输出,都是通过获取dom的方式去获取到元素里面的内容,但是在浏览器上打印确实不同的,控制台上的输出是:
前端同学
我是测试同学
这里就有疑问了 明明我已经改变了name的值,而我的输出还是‘前端同学’呢?
通过上面的例子我们就不难得出结论了,大概也明白this.nextTick是怎么使用了,但是其中的原理是什么,我总结了如下几条,代表个人理解:
- dom更新:在vue中,你修改了data的某一个值,并不会立即反应到该ele中。vue将你对data的更 改放到watcher的一个对列中(异步),只有在当前任务空闲时才会去执行watcher队列任务。这就有一个延迟时间了。
- 当执行到nextTick的时候,这是一个异步任务,异步任务是不会立即执行的,会被js处理器放到一个队列里,按照队列的顺序优先级等一个个按照次序执行,新添加的事件都会放在队列末尾。所以,当第一个也就是data的修改执行渲染在页面之后,这个时候执行nextTick,就肯定能获取dom。(这里涉及到了js的事件执行机制,在以后的文章中我也会更新)
3、this.$nextTick与setTimeout的区别
this.$nextTick()优先于setTimeout执行的,这两者是分属不同队列的,nextTick 在vue 源码中是利用 Promise.resolve()实现的
this.nextTick(),Promise是属于微队列
setTimeout ; setInterval ; setImmediate是属于宏队列
这就不难理解this.$nextTick()优先于setTimeout执行,因为js是单线程的,在执行js代码的时候, 全局的js代码是个宏任务, 遇到同步的就执行,异步的就分别放入对应的任务队列中去; 等到全局的js代码的同步执行完成后,就开始找微队列里的微任务,等到微任务执行完成后,才开始执行宏队列的宏任务;
总结:
Vue的特点之一就是能实现响应式,但数据更新时,DOM不会立即更新,而是放入一个异步队列中,因此如果在我们的业务场景中,有一段代码里面的逻辑需要在DOM更新之后才能顺利执行,这个时候我们可以使用this.$nextTick() 函数来实现。