Vue的nextTick是什么?
公司做之前项目的时候,遇到了一些比较困惑的问题,后来研究明白了nextTick的用法。
我们先看两种情况:
第一种:
export default {
data () {
return {
msg: 0
}
},
mounted () {
this.msg = 1
this.msg = 2
this.msg = 3
},
watch: {
msg () {
console.log(this.msg)
}
}
}
这段脚本执行我们猜测会依次打印:1、2、3。但是实际效果中,只会输出一次:3。为什么会出现这样的情况?
原因:
当触发update
更新的时候,会去执行queueWatcher
方法,也就是说,下一个循环开始时调用,此时msg已经变成3了。
保证更新视图操作DOM的动作是在当前栈执行完以后下一个Tick(或者是当前Tick的微任务阶段)的时候调用,大大优化了性能。
第二种情况:
<body>
<div id="main">
<ul class="list">
<li class="item" v-for="item in list">{{ item }}</li>
</ul>
</div> <script>
new Vue({
el: '#main',
data: {
list: [
'AAAAAAAAAA',
'BBBBBBBBBB',
'CCCCCCCCCC'
]
},
mounted: function () {
this.list.push('DDDDD')
}
})
</script>
</body>
随便给了点样式之后,页面是这样的:
看起来似乎一切正常,我们在给数组添加了一条数据之后,页面也确实对应的更新了。可是,当我们在打印这个 ul 元素里 li 的 length 时,问题出现了:
mounted: function () {
this.list.push('DDDDD')
console.log(this.$el.querySelectorAll('.item').length) //
}
这时候如果我们有需求需要通过 li 的个数来计算出 ul 容器的高度来进行布局,显然就有问题了。
而这时候 Vue 的 nextTick 就可以帮助我们解决这个问题:
mounted: function () {
this.list.push('DDDDD')
Vue.nextTick(function() {
console.log(this.$el.querySelectorAll('.item').length) //
// ... 计算
})
当你设置 vm.someData = 'new value' ,该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
js 是单线程语言
我们都知道,js 执行的所有任务都需要排队,一个任务必须要等它前面的一个任务执行完之后才能执行。如果前一个任务需要花费大量的时间来计算,那么后一个任务就必须一直等它执行完才会轮到它执行,这就是单线程的特性。 而 js 的任务分为两种,同步任务和异步任务:
- 同步任务就是按照顺序一个一个的执行任务,后一个任务要执行必须等它前一个任务完成
- 异步任务(比如回调)不会占用主线程,会被塞到一个任务队列,等主线程的任务执行完毕,就会把这个异步任务队列里的任务放回主线程依次执行
用一个丑但易懂的图来表示:
所以结果输出是这样就很好理解了:
Event Loop(事件循环)
被称作事件循环的原因在于,同步的任务可能会生成新的任务,因此它一直在不停的查找新的事件并执行。一次循环的执行称之为 tick,在这个循环里执行的代码被称作 task,而整个过程是不断重复的。
console.log(1); setTimeout(()=>{
console.log(2);
},1000); while (true){}
上面代码在输出 1 之后(谨慎使用!我的浏览器就被卡死了~),定时器被塞到任务队列里,然后主线程继续往下执行,碰到一个死循环,导致任务队列里的任务永远不会被执行,因此不会输出 2
事件队列
除了我们的主线程之外,任务队列分为 microtask 和 macrotask,通常我们会称之为微任务和宏任务。 microtask 这一名词在js中是个比较新的概念,我们通常是在学习 ES6 的 Promise 时才初次接触到。
- 执行优先级上,主线程任务 > microtask > macrotask。
- 典型的 macrotask 有 setTimeout 和 setInterval,以及只有 IE 支持的 setImmediate,还有 MessageChannel等,ES6的 Promise 则是属于 microtask
console.log(1) setTimeout(function(){
console.log(2)
}) Promise.resolve().then(function(){
console.log('promise1')
}).then(function(){
console.log('promise2')
}) console.log(4)
根据执行顺序,上面代码的输出结果很容易就能得出了:
nextTick
让我们回到上面的主题,Vue 的 nextTick方法,
从 源码 不难发现,Vue 在内部尝试对异步队列使用原生的setImmediate
和MessageChannel和
,Promise.then
如果当前执行环境不支持,就采用setTimeout(fn, 0)
代替。
什么时候需要用Vue.nextTick()
:
- 你在
Vue
生命周期的created()钩子函数进行的DOM
操作一定要放在Vue.nextTick()
的回调函数中。原因是什么呢,原因是在created()
钩子函数执行的时候DOM
其实并未进行任何渲染,而此时进行DOM
操作无异于徒劳,所以此处一定要将DOM
操作的js
代码放进Vue.nextTick()
的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM
挂载和渲染都已完成,此时在该钩子函数中进行任何DOM
操作都不会有问题 。 - 在数据变化后要执行的某个操作,当你设置
vm.someData = 'new value'
,DOM
并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM
更新。如果此时你想要根据更新的DOM
状态去做某些事情,就会出现问题。。为了在数据变化之后等待Vue
完成更新DOM
,可以在数据变化之后立即使用Vue.nextTick(callback)
。这样回调函数在DOM
更新完成后就会调用。 mounted
不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用vm.$nextTick
替换掉mounted
:
mounted: function () {
this.$nextTick(function () { // Code that will run only after the
// entire view has been rendered
})
}
最新文章
- 张高兴的 UWP 开发笔记:汉堡菜单进阶
- 搭建Linux+Jexus+MariaDB+ASP.NET[LJMA]环境
- iOS开发者账号配置进行设备调试
- ng-bind-html 的原素没有高度
- ASP.NET MVC:窗体身份验证及角色权限管理示例
- java基本类型转换规则
- 放到u-boot/arch/arm/inlcude下面解压A20固件库制作笔记
- ElasticSearch 常用的查询过滤语句
- Egret 双端接入爱贝支付遇到的问题
- 关于hibernate中对象的三种状态分析
- Chapter 2 Open Book&mdash;&mdash;26
- jquery easyui combobox 高度自适应
- Liunx find/locate/whereis/which 总结
- dva中roadhog版本升级后带来的问题及解决方法
- vue框架中的日期组件转换为yyy-mm-dd格式
- css3 特效拓展 画个安卓机器人
- 开启safe_mode之后对php系统函数的影响
- Spyder 调出绘图界面
- MongoDB简单使用 —— 基本操作
- 利用Django做一个简单的分页页面
热门文章
- Java-JVM 栈帧(Stack Frame)
- FinalShell Mac OS版,Linux版安装及教程(Mac下的xshell)
- AMBARI部署HADOOP集群(4)
- CentOS7性能监控系统安装
- 190628 - 解决新版本LastPass没有谷歌套件时打开就闪退的问题.md
- Eclipse使用高版本的jdk编译低版本的class文件的方法
- Python:Base1(数据类型,print语句,变量,定义字符串,raw字符串与多行字符串,Unicode字符串,整数和浮点数运算,布尔类型运算)
- 【.NET】CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\d29b5393\123c3a1c\App_Code.odl3w4o6.dll”--“拒绝访问。 ”
- MaxScale中间件部署数据库读写分离
- 解析之Apache解析