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 相关文章推荐
js的逻辑运算符 ||
May 31 Javascript
防止按钮在短时间内被多次点击的方法
Mar 10 Javascript
jQuery使用Selectator插件实现多选下拉列表过滤框(附源码下载)
Apr 08 Javascript
ES6学习笔记之Set和Map数据结构详解
Apr 07 Javascript
React实践之Tree组件的使用方法
Sep 30 Javascript
vue中v-for通过动态绑定class实现触发效果
Dec 06 Javascript
浅谈JS和jQuery的区别
Mar 27 jQuery
VuePress 中如何增加用户登录功能
Nov 29 Javascript
vue仿淘宝滑动验证码功能(样式模仿)
Dec 10 Javascript
原生js实现碰撞检测
Mar 12 Javascript
JS实现放大镜效果
Sep 21 Javascript
antd design table更改某行数据的样式操作
Oct 31 Javascript
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来限制每个ip每天浏览页面数量的实现思路
2015/02/24 PHP
[原创]php使用curl判断网页404(不存在)的方法
2016/06/23 PHP
PHP实现针对日期,月数,天数,周数,小时,分,秒等的加减运算示例【基于strtotime】
2017/04/19 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
javascript 写类方式之七
2009/07/05 Javascript
从零开始学习jQuery (四) jQuery中操作元素的属性与样式
2011/02/23 Javascript
document.forms[].submit()使用介绍
2014/02/19 Javascript
js中settimeout方法加参数的使用实例
2014/02/27 Javascript
JavaScript截取、切割字符串的技巧
2016/01/07 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
2016/05/18 Javascript
微信小程序  生命周期详解
2016/10/27 Javascript
bootstrapValidator表单验证插件学习
2016/12/30 Javascript
angular4中关于表单的校验示例
2017/10/16 Javascript
AngularJS 多指令Scope问题的解决
2018/10/25 Javascript
详解vue中的computed的this指向问题
2018/12/05 Javascript
使用koa2创建web项目的方法步骤
2019/03/12 Javascript
20多个小事例带你重温ES10新特性(小结)
2019/09/29 Javascript
[02:28]DOTA2亚洲邀请赛附加赛 RECAP赛事回顾
2015/01/29 DOTA
[02:53]2018年度DOTA2最佳战队-完美盛典
2018/12/17 DOTA
浅谈python爬虫使用Selenium模拟浏览器行为
2018/02/23 Python
通过python将大量文件按修改时间分类的方法
2018/10/17 Python
Python求两个字符串最长公共子序列代码实例
2020/03/05 Python
pycharm sciview的图片另存为操作
2020/06/01 Python
推荐一些比较有用的css3新属性
2014/11/11 HTML / CSS
大学生职业生涯规划书模板
2014/01/03 职场文书
法律专业应届生自荐信范文
2014/01/06 职场文书
中学生运动会入场词
2014/02/12 职场文书
好书伴我成长演讲稿
2014/05/14 职场文书
爱我中华演讲稿
2014/05/20 职场文书
后备干部培训方案
2014/05/22 职场文书
中韩经贸翻译专业大学生职业生涯规划范文
2014/09/18 职场文书
2014党员干部四风问题对照检查材料思想汇报
2014/09/24 职场文书
评奖评优个人先进事迹材料
2015/11/04 职场文书
乔迁新居祝福语
2019/11/04 职场文书
Python深度学习之Pytorch初步使用
2021/05/20 Python
vue本地构建热更新卡顿的问题“75 advanced module optimization”完美解决方案
2022/08/05 Vue.js