# 响应式原理
概述
响应式就是在修改数据对象的时候会触发视图更新
# 追踪变化
原理
Vue 会遍历 data 选项中所有 property
,然后使用 Object.defineProperty
设置所有 property
的自定义 getter/setter
,触发 setter
会通知 watcher
使得相关联的组件重新渲染

# 检测变化的特殊情况
# 对象
无法检测对象属性的添加或刪除,所以
- 在初始化的时候声明:
var vm = new Vue({
data: {
a: 1,
},
});
// `vm.a` 是响应式的
vm.b = 2;
// `vm.b` 是非响应式的
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 添加单个属性,使用
$set
添加响应式属性:
this.$set(this.someObject, "b", 2);
1
- 添加多个属性,和原对象混合创建新的对象:
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 });
1
2
2
# 数组
Vue
不能检测以下数组的变动:
- 利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
- 使用
$set
修改:Vue.set(vm.items, indexOfItem, newValue)
- 使用
splice
:vm.items.splice(indexOfItem, 1, newValue)
- 使用
- 修改数组的长度时,例如:
vm.items.length = newLength
- 使用
splice
:vm.items.splice(newLength)
- 使用
# 异步更新队列
Vue
在更新 DOM
时是异步执行的:
- 监听到数据变化
- 开启队列
- 缓存同一事件循环中发生的所有数据变更(同一个
watcher
多次触发只会被加入到队列一次) - 下一次事件循环
tick
中刷新队列执行去重后的任务
注
Vue
在内部对异步队列尝试使用原生的 Promise.then
、MutationObserver
和 setImmediate
,如果执行环境不支持,则会采用 setTimeout(fn, 0)
代替
如果想要基于更新后的 DOM
状态来做点什么,可以在数据变化之后立即使用 Vue.nextTick(callback)
,这样回调函数将在 DOM
更新完成后被调用
(2.6 之前的版本)
Vue.nextTick
一般情况下是微任务,在处理事件绑定的时候是宏任务(事件冒泡可能导致顺序错误)
最新的冒泡做了特殊处理,所有都是微任务
# proxy
和 defineproperty
相比优势
优势:
- 可以直接监听对象而非属性
- 可以直接监听数组变化
- 有 13 种拦截方法
- 返回一个新对象,对新对象操作,而
defineproperty
只能遍历对象属性直接修改 - 作为新标准将会收到浏览器厂商重点持续的性能优化
劣势:
defineproperty
兼容性好,ie9
,无法通过polyfill
实现