深入响应式原理

现在是时候深入一下了!Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接,不过理解其工作原理同样重要,这样你可以回避一些常见的问题。在这个章节,我们将进入一些 Vue 响应式系统的底层的细节。

如何追踪变化

当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。这里需要注意的问题是浏览器控制台在打印数据对象时 getter/setter 的格式化并不同,所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。

每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

检测变化的注意事项

受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。例如:

var vm = new Vue({data:{a:1}
})// `vm.a` 是响应的vm.b = 2
// `vm.b` 是非响应的

Vue 不允许在已经创建的实例上动态添加新的根级响应式属性 (root-level reactive property)。然而它可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上:

Vue.set(vm.someObject, 'b', 2)

您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

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

有时你想向一个已有对象添加多个属性,例如使用 Object.assign() 或 _.extend() 方法来添加属性。但是,这样添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新的属性:

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

也有一些数组相关的问题,之前已经在列表渲染中讲过。

声明响应式属性

由于 Vue 不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值:

var vm = new Vue({data: {// 声明 message 为一个空值字符串message: ''},template: '<div>{{ message }}</div>'
})
// 之后设置 `message`
vm.message = 'Hello!'

如果你未在 data 选项中声明 message,Vue 将警告你渲染函数正在试图访问的属性不存在。

这样的限制在背后是有其技术原因的,它消除了在依赖项跟踪系统中的一类边界情况,也使 Vue 实例在类型检查系统的帮助下运行的更高效。而且在代码可维护性方面也有一点重要的考虑:data 对象就像组件状态的概要,提前声明所有的响应式属性,可以让组件代码在以后重新阅读或其他开发人员阅读时更易于被理解。

异步更新队列

可能你还没有注意到,Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用 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 对象,所以你可以使用新的 ES2016 async/await语法完成相同的事情:

methods: {async updateMessage: function () {this.message = 'updated'console.log(this.$el.textContent) // => '未更新'await this.$nextTick()console.log(this.$el.textContent) // => '已更新'}
}

from:https://cn.vuejs.org/v2/guide/reactivity.html

Vue.js 深入响应式原理相关推荐

  1. Vue数据绑定和响应式原理

    Vue数据绑定和响应式原理 当实例化一个Vue构造函数,会执行 Vue 的 init 方法,在 init 方法中主要执行三部分内容,一是初始化环境变量,而是处理 Vue 组件数据,三是解析挂载组件.以 ...

  2. Vue 2.x 响应式原理与双向绑定

    Vue实例 Vue会把data中的数据成员注入到Vue的实例中去,并转成getter/setter访问器属性. 这样的目的是: 1.我们能够通过 this.xxx(this.属性名)的方式进行调用. ...

  3. 基于vue的响应式ui框架_基于Vue.js的响应式和可配置UI框架

    基于vue的响应式ui框架 Framevuerk (Framevuerk) Fast, Responsive, Multi Language, Both Direction Support and C ...

  4. Vue.js响应式原理

    Vue.js响应式原理 框架 浏览数:659 2017-9-20 关于Vue.js Vue.js是一款MVVM框架,上手快速简单易用,通过响应式在修改数据的时候更新视图.Vue.js的响应式原理依赖于 ...

  5. 初始Vue响应式原理~~

    自从 Vue 发布以来,就受到了广大开发人员的青睐,提到 Vue,我们首先想到的就是 Vue 的响应式系统,那响应式系统到底是怎么回事呢?接下来我就给大家简单介绍一下 Vue 中的响应式原理. vue ...

  6. Vue源码解读一:Vue数据响应式原理

    这方面的文章很多,但是我感觉很多写的比较抽象,本文会通过举例更详细的解释.(此文面向的Vue新手们,如果你是个大牛,看到这篇文章就可以点个赞,关掉页面了.)通过阅读这篇文章,你将了解到: 1.Vue数 ...

  7. 深入了解Vue 2响应式原理,并手写一个简单的Vue

    1. Vue 2的响应式原理 Vue.js 一个核心思想是数据驱动.所谓数据驱动是指视图是由数据驱动生成的,对视图的修改,不会直接操作 DOM,而是通过修改数据.vue.js里面只需要改变数据,Vue ...

  8. 一篇文章带你吃透VUE响应式原理

    本篇响应式原理介绍比较长,全文大概1w+字.虽然内容繁杂,但阅读过后,绝对会让你对vue的响应式有更加深刻的理解. 分块阅读,效果更佳.(建议读者有一定vue使用经验和基础再食用) 首先上图,下面这张 ...

  9. 详细介绍Vue的数据响应式

    Vue.js的核心包括一套"响应式系统"."响应式",是指当数据改变后,Vue会通知到使用该数据的代码.例如,视图渲染中使用了数据,数据改变后,视图也会自动更新 ...

最新文章

  1. mysql案例_MySQL实例crash的案例详细分析
  2. python阶乘匿名函数_python的高阶函数与匿名函数
  3. Vue——显示微信用户名称中enjoin表情
  4. HTML文本错位,DIV+CSS网页错位诊断和解决方法
  5. 企业级应用框架(五)IOC容器在框架中的应用
  6. 饿了么超时20分钟_饿了么回应“多等5分钟”,网友气炸了
  7. 喂,315吗?我花299元买到一只人工智障!
  8. linux django 安装mysql_Linux下安装Python3和django并配置mysql作为django默认服务器
  9. [Android]Android TraceView工具使用
  10. ubuntu /etc/profile和/etc/environment的比较
  11. RF-接口自动化测试-「Body Data格式」
  12. Springboot集成Quartz定时任务,项目启动执行任务
  13. 电路基础-6(电容、电感、一阶电路)
  14. 软件开发每个阶段的任务以及产生的文档
  15. 解密excel.xls文件密码
  16. 【经验分享】如何使用校园账号登录WOS(Web of Science)
  17. 使用wxPython开发带有GUI图形界面的Python程序简单实例
  18. 尚硅谷-谷粒商城-电商项目-秒杀系统-笔记
  19. 二叉树面试题:前中序求后序、中后序求前序
  20. 20220719暑假实习笔记

热门文章

  1. 分布式服务框架 Zookeeper -- 管理分布式环境中的数据--转载
  2. 金融风控实战——特征工程上
  3. 【ETL】ETL----如何决定是否采用ETL工具
  4. 【大数据-Hadoop】Presto
  5. Transformer-XL解读(论文 + PyTorch源码)
  6. 深度学习入门教程UFLDL学习实验笔记三:主成分分析PCA与白化whitening
  7. 深度学习 vs. 大数据:神经网络权值的版权属于谁?
  8. iis 7 php_Windows server 2008 下基于IIS7配置php7.2运行环境
  9. 实战SSM_O2O商铺_35【商品】商品编辑之View层的实现
  10. TextInputLayout-Android M新控件