您对nextTick的原理的有了解过吗? 今天我们一起来学习下吧。
官方定义
在下次 DOM 更新循环结束之后执行延时回调,在修改数据之后使用这个方法,获取更新后的最新 DOM。
nextTick是 Vue 提供的一个全局 Api,由于 vue 的异步更新策略导致我们修改数据不会立即体现在 DOM 的变化上,此时如果想要立即获取更新后的 DOM 状态,就需要使用这个方法。
Vue 在更新 DOM 的时候是异步的,只要我们监听到数据的变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生所以数据变更,如果一个 watcher 被多次触发,只会被推入到队列中一次。
这种在缓冲时去重对于不必要的计算和 DOM 操作是非常重要的,nextTick 方法中添加回调方法会在队列中加入一个回调函数,确保在前面的 DOM 操作完成之后才调用。
nextTick 简单原理
它会在 callbacks 里面加入我们的回调函数,然后子啊 timeFunc 异步方式调用他们,首先选择的是 Promise。
这样就可以在 nextTick 中看到 dom 操作结果。
nextTick解析
异步说明
简单来说异步执行的运行机制:
-
所有同步任务在主线程执行,形成一个执行栈
-
主线程之外存在一个任务队列,用于存异步任务运行结果事件
-
执行栈所有同步任务执行完毕,系统就会任务队列里面事件
-
主线程重复上面动作
事件循环说明
简单来说,Vue在修改数据后,视图不会立即更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新
nextTick 用途
应用场景:需要在视图更新之后,基于新的视图进行操作
注意:在created和mounted阶段,如果需要操作渲染后的视图,也要使用nextTick 方法。
官方文档说明:
注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
其他应用场景
点击按钮显示原本以 v-show = false 隐藏起来的输入框,并获取焦点。
// 会报错,修改为 nextTick
showsou(){
this.showit = true //修改 v-show
document.getElementById("keywords").focus() //在第一个 tick 里,获取不到输入框,自然也获取不到焦点
}
// 修改
showsou(){
this.showit = true
this.$nextTick(function () {
// DOM 更新了
document.getElementById("keywords").focus()
})
}
点击获取元素宽度。
<div id="app">
<p ref="myWidth" v-if="showMe">{{ message }}</p>
<button @click="getMyWidth">获取p元素宽度</button>
</div>
getMyWidth() {
this.showMe = true;
//this.message = this.$refs.myWidth.offsetWidth;
//报错 TypeError: this.$refs.myWidth is undefined
this.$nextTick(()=>{
//dom元素更新后执行,此时能拿到p元素的属性
this.message = this.$refs.myWidth.offsetWidth;
})
}
使用 swiper 插件通过 ajax 请求图片后的滑动问题。
总结
a、在同一事件循环中,只有所有的数据更新完毕,才会调用nextTick;
b、仅在同步执行环境数据完全更新完毕,DOM才开始渲染,页面才开始展现;
c、在同一事件循环中,如果存在多个nextTick,将会按最初的执行顺序进行调用;
从用例1+用例4得出:
d、从同步执行环境中的四个tick对应的'li'数量均为30000可看出,同一事件循环中,nextTick所在的视图是相同的;
从用例2得出:
e、只有同步环境执行完毕,DOM渲染完毕之后,才会处理异步callback
从用例3得出:
f、每个异步callback最后都会处在一个独立的事件循环中,对应自己独立的nextTick;
从用例1结论中可得出:
g、这个事件环境中的数据变化完成,在进行渲染[视图更新],可以避免DOM的频繁变动,从而避免了因此带来的浏览器卡顿,大幅度提升性能;
从b可以得出:
h、在首屏渲染、用户交互过程中,要巧用同步环境及异步环境;首屏展现的内容,尽量保证在同步环境中完成;其他内容,拆分到异步中,从而保证性能、体验。
Tips:
1、可产生异步callback的有:promise(microtask queue)、setTimeout、MutationObserver、DOM事件、Ajax等;
2、 vue DOM的视图更新实现,,使用到了ES6的Promise及HTML5的MutationObserver,当环境不支持时,使用setTimeout(fn, 0)替代。上述的三种方法,均为异步API。其中MutationObserver类似事件,又有所区别;事件是同步触发,其为异步触发,即DOM发生变化之后,不会立刻触发,等当前所有的DOM操作都结束后触发。关于异步API、事件循环将在以后补充。