Vue中this.$nextTick的作用及用法


Posted in Javascript onFebruary 04, 2020

Vue实现响应式后DOM的变化

data对象中数据改变是如何追踪的?

vue将遍历data对象中所有的属性,并通过 Object.defineProperty 把这些属性全部转为 getter/setter;但是我们是没有办法看到 getter/setter的,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。

每个组件都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

Vue是无法检测到data对象属性的添加和删除

原因:Vue在对初始化组件时会对对象属性执行getter/setter转化,所以属性必须在data对象上存在才能让Vue将它转化为初始化。

var vm = new Vue({
 data:{
 a:1
 }
 })

 // `vm.a` 是响应式的

 vm.b = 2
 // `vm.b` 是非响应式的

如何动态添加根级别的响应式属性【就是对data添加属性】

this.$set(this.someObject,'b',2)

异步更新队列

Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。

如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。

然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。

Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。

例如,当你设置 vm.someData = 'new value',该组件不会立即重新渲染。

当刷新队列时,组件会在下一个事件循环“tick”中更新。

多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。例如:

<div id="example">{{message}}</div>
 var vm = new Vue({
  el: '#example',
  data: {
  message: '123'
  }
 })
 vm.message = 'new message' // 更改数据
 vm.$el.textContent === 'new message' // false
 Vue.nextTick(function () {
  vm.$el.textContent === 'new message' // true
 })

在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上:

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
  return {
   message: '未更新'
  }
  },
  methods: {
  updateMessage: function () {
   this.message = '已更新'
   console.log(this.$el.textContent) // => '未更新'
   this.$nextTick(function () {
   console.log(this.$el.textContent) // => '已更新'
   })
  }
  }
 })

因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2017 async/await 语法完成相同的事情:

methods: {
updateMessage: async function () {

this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}

Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。

$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM

实例化理解Vue响应化

<div id="app">

<div>Price :¥{{ price }}</div>
<div>Total:¥{{ price * quantity }}</div>
<div>Taxes: ¥{{ totalPriceWithTax }}</div>
<button @click="changePrice">改变价格</button>
</div>
var app = new Vue({
el: '#app',
data() {

return {
 price: 5.0,
 quantity: 2
};
},
computed: {

totalPriceWithTax() {
 return this.price * this.quantity * 1.03;
}
},
methods: {

changePrice() {
 this.price = 10;
}
}
})

上例中当price 发生变化的时候,Vue就知道自己需要做三件事情:

  • 更新页面上price的值
  • 计算表达式 price*quantity 的值,更新页面
  • 调用totalPriceWithTax 函数,更新页面

数据发生变化后,会重新对页面渲染,这就是Vue响应式,那么这一切是怎么做到的呢?

想完成这个过程,我们需要:

  • 侦测数据的变化
  • 收集视图依赖了哪些数据
  • 数据变化时,自动“通知”需要更新的视图部分,并进行更新

对应专业俗语分别是:

  • 数据劫持 / 数据代理
  • 依赖收集
  • 发布订阅模式

总结

再来回顾下整个过程:

Vue中this.$nextTick的作用及用法

在new Vue()后, Vue 会调用_init函数进行初始化,也就是init 过程,在 这个过程Data通过Observer转换成了getter/setter的形式,来对数据追踪变化,当被设置的对象被读取的时候会执行getter函数,而在当被赋值的时候会执行setter函数。

当外界通过Watcher读取数据时,会触发getter从而将Watcher添加到依赖中。

在修改对象的值的时候,会触发对应的setter,setter通知之前依赖收集得到的 Dep 中的每一个 Watcher,告诉它们自己的值改变了,需要重新渲染视图。这时候这些 Watcher就会开始调用update来更新视图。

以上就是本次介绍的全部相关知识点内容,如果大家学习中有任何补充可以联系三水点靠木小编。

Javascript 相关文章推荐
jquery 插件之仿“卓越亚马逊”首页弹出菜单效果
Dec 25 Javascript
jQuery实现点击该行即可删除HTML表格行
Oct 17 Javascript
总结AngularJS开发者最常犯的十个错误
Aug 31 Javascript
jQuery中$.ajax()方法参数解析
Oct 22 Javascript
jQuery插件FusionCharts绘制的2D双面积图效果示例【附demo源码】
Apr 11 jQuery
Vue中render函数的使用方法
Jan 31 Javascript
浅谈实现vue2.0响应式的基本思路
Feb 13 Javascript
js+css实现打字效果
Jun 24 Javascript
jQuery中将json数据显示到页面表格的方法
May 27 jQuery
js中arguments对象的深入理解
May 14 Javascript
微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法
Aug 01 Javascript
Vue组件生命周期运行原理解析
Nov 25 Vue.js
JS中this的4种绑定规则详解
Feb 04 #Javascript
详解JavaScript中精度失准问题及解决方法
Feb 04 #Javascript
Preload基础使用方法详解
Feb 03 #Javascript
使用PreloadJS加载图片资源的基础方法详解
Feb 03 #Javascript
使用preload预加载页面资源时注意事项
Feb 03 #Javascript
jQuery实现小火箭返回顶部特效
Feb 03 #jQuery
JS常用正则表达式超全集(密码强度校验,金额校验,IE版本,IPv4,IPv6校验)
Feb 03 #Javascript
You might like
php绘图中显示不出图片的原因及解决
2014/03/05 PHP
PHP封装的完整分页类示例
2018/08/21 PHP
PDO::errorInfo讲解
2019/01/28 PHP
OfflineSave离线保存代码再次发布使用说明
2007/05/23 Javascript
Jquery中LigerUi的弹出编辑框(实现方法)
2013/07/09 Javascript
getAsDataURL在Firefox7.0下无法预览本地图片的解决方法
2013/11/15 Javascript
JavaScript中对象property的删除方法介绍
2014/12/30 Javascript
详解JavaScript对Date对象的操作问题(生成一个倒数7天的数组)
2015/10/01 Javascript
Bootstrap教程JS插件滚动监听学习笔记分享
2016/05/18 Javascript
jQuery与JS加载事件用法分析
2016/09/04 Javascript
详解AngularJS验证、过滤器、指令
2017/01/04 Javascript
关于jQuery库冲突的完美解决办法
2017/05/20 jQuery
快速掌握jquery分页插件jqPaginator的使用方法
2017/08/09 jQuery
浅谈Angular4中常用管道
2017/09/27 Javascript
浅谈ng-zorro使用心得
2018/12/03 Javascript
[07:26]2015国际邀请赛第二日TOP10集锦
2015/08/06 DOTA
介绍Python的Urllib库的一些高级用法
2015/04/30 Python
Python实现带百分比的进度条
2016/06/28 Python
python 请求服务器的实现代码(http请求和https请求)
2018/05/25 Python
一行代码让 Python 的运行速度提高100倍
2018/10/08 Python
python PyQt5/Pyside2 按钮右击菜单实例代码
2019/08/17 Python
pytorch 实现cross entropy损失函数计算方式
2020/01/02 Python
浅谈numpy中np.array()与np.asarray的区别以及.tolist
2020/06/03 Python
纽约复古灵感的现代珠宝品牌:Lulu Frost
2018/03/03 全球购物
PHP如何去执行一个SQL语句
2016/03/05 面试题
什么是serialVersionUID
2016/03/04 面试题
教育专业个人求职信
2013/12/02 职场文书
致200米运动员广播稿
2014/02/06 职场文书
2014年医生工作总结
2014/11/21 职场文书
2015年八一建军节演讲稿
2015/03/19 职场文书
周恩来的四个昼夜观后感
2015/06/03 职场文书
国富论读书笔记
2015/06/26 职场文书
母亲节主题班会
2015/08/14 职场文书
2016清明节森林防火广播稿
2015/12/17 职场文书
暑假开始了,你的暑假学习计划写好了吗?
2019/07/04 职场文书
uniapp开发打包多端应用完整方法指南
2022/12/24 Javascript