Vue.2.0.5-深入响应式原理
大部分的基础内容我们已经讲到了,现在讲点底层内容。Vue 最显著的一个功能是响应系统 —— 模型只是普通对象,修改它则更新视图。这会让状态管理变得非常简单且直观,不过理解它的原理以避免一些常见的陷阱也是很重要的。在本节中,我们将开始深挖 Vue 响应系统的底层细节。
如何追踪变化
把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。这是 ES5 的特性,不能打补丁实现,这便是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。
用户看不到 getter/setters,但是在内部它们让 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 properties)。然而它可以使用 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 对象就像组件状态的模式(Schema),在它上面声明所有的属性让组织代码更易于被其他开发者或是自己回头重新阅读时更加快速地理解。
异步更新队列
你应该注意到 Vue 执行 DOM 更新是异步的,只要观察到数据变化,Vue 就开始一个队列,将同一事件循环内所有的数据变化缓存起来。如果一个 watcher 被多次触发,只会推入一次到队列中。然后,在接下来的事件循环中,Vue 刷新队列并仅执行必要的 DOM 更新。Vue 在内部尝试利用原生的 Promise.then 和 MutationObserver 来调用异步队列,如果执行环境不兼容,会采用 setTimeout(fn, 0) 代替。
例如,当你设置 vm.someData = 'new value' ,该组件不会马上被重新渲染。当刷新队列时,这个组件会在下一次事件循环清空队列时更新。我们基本不用关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。一般来讲, Vue 鼓励开发者沿着数据驱动的思路,尽量避免直接接触 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: 'not updated'
}
},
methods: {
updateMessage: function () {
this.message = 'updated'
console.log(this.$el.textContent) // => 'not updated'
this.$nextTick(function () {
console.log(this.$el.textContent) // => 'updated'
})
}
}
})
Vue.2.0.5-深入响应式原理的更多相关文章
- Vue.js学习 Item12 – 内部响应式原理探究
深入响应式原理 大部分的基础内容我们已经讲到了,现在讲点底层内容.Vue.js 最显著的一个功能是响应系统 —— 模型只是普通对象,修改它则更新视图.这让状态管理非常简单且直观,不过理解它的原理也很重 ...
- 深入浅出Vue基于“依赖收集”的响应式原理(转)
add by zhj: 文章写的很通俗易懂,明白了Object.defineProperty的用法 原文:https://zhuanlan.zhihu.com/p/29318017 每当问到VueJS ...
- 【Vue源码学习】响应式原理探秘
最近准备开启Vue的源码学习,并且每一个Vue的重要知识点都会记录下来.我们知道Vue的核心理念是数据驱动视图,所有操作都只需要在数据层做处理,不必关心视图层的操作.这里先来学习Vue的响应式原理,V ...
- vue2.0 之 深入响应式原理
实例demo<div id="app"> <span>{{a}}</span> <input type="text" ...
- vue源码解析之响应式原理
关于defineReactive等使用细节需要自行了解 一些关键知识点 $mount时 会 new Watcher 把组件的 updateComponent 方法传给watcher 作为getter ...
- Vue 2.0 与 Vue 3.0 响应式原理比较
Vue 2.0 的响应式是基于Object.defineProperty实现的 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 prop ...
- vue.js响应式原理解析与实现
vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...
- vue深入响应式原理
vue深入响应式原理 深入响应式原理 — Vue.jshttps://cn.vuejs.org/v2/guide/reactivity.html 注意:这里说的响应式不是bootsharp那种前端UI ...
- 深度解析 Vue 响应式原理
深度解析 Vue 响应式原理 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还是进 ...
随机推荐
- HDU 1166敌兵布阵+NOJv2 1025: Hkhv love spent money(线段树单点更新区间查询)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- CSS3系列:流式(弹性)布局(flex布局)
我的新伸缩盒子.http://www.cnblogs.com/leee/p/5533436.html
- linux下挂在u盘,移动硬盘的方法,转移服务器资料的时候,使用移动硬盘什么最方便了
本文章是在centos环境下操作的 最近linux服务器我不小心吧root下面的用户配置,不能远程登录,而且我对linux系统配置也不熟悉,最后的办法就是去了一趟机房,还好是在深圳南山科技园,不算太远 ...
- ibatis动态sql配置启动时提示:The content of elements must consist of well-formed character data...
ibatis动态sql配置启动时提示:The content of elements must consist of well-formed character data... 2012-07-18 ...
- linux系统
● ubuntu提示"sudo: unable to resolve host volcano: No such file or directory" 修改/etc/hosts,在 ...
- CodeForces 621C 数学概率期望计算
昨天训练赛的题..比划了好久才想出来什么意思 之前想的是暴力for循环求出来然后储存数组 后来又想了想 自己萌的可以.. 思路就是求出来每个人与他的右边的人在一起能拿钱的概率(V(或)的关系)然后*2 ...
- [办公自动化]如何对Excel表格顶部设计
领导有一个excel要完成如下功能:顶部要包含企业LOGO,还要包含设计图号.版次等表格,还要包含类似“第 页 of 页” 总体思路: 1.利用顶端标题行完成除了页码以外的所有事情:(当然也可以利 ...
- 推荐25款php中非常有用的类库
推荐25款php中非常有用的类库 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014-09-29 作为一个PHP开发者,现在是一个令人激动的时刻.每天有许许多多有用的库分发出 ...
- PHP程序员函数注释规格(麻烦大家遵守)
PHP程序员函数注释规格(麻烦大家遵守) 以前我也不愿意写注释,但是2个月后发现自己写的什么都不知道了.. 为了宇宙的发展,为了二次开发的便捷,为了代码的可读性,建议大家把注释写好.. <? ...
- Centos下安装Scrapy
Scrapy是一个开源的机遇twisted框架的python的单机爬虫,该爬虫实际上包含大多数网页抓取的工具包,用于爬虫下载端以及抽取端. 安装环境: centos5.4 python2.7.3 安装 ...