何为数据响应式
首先
const vm = new Vue({options}) //
当vm/options发生了变化(用户进行了互动)或(options内的变化-->使用props),用户/开发者都会得到-->响应,Vue 会通知到使用该数据的代码。
Vue将注入的组件/数据进行封装,当触发了相关的setter,则与之关联的组件/view会重新渲染-->数据和视图互相响应变化(对于UI控件来说)
!!Vue 在更新 DOM 时是异步执行的!!
Vue 2.0 响应式原理--Object.defineProperty
当把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用Object.defineProperty() 把这些 property 全部转为 getter/setter。
每个实例都有对应的 watcher 实例,它会在组件渲染的过程中把接触过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,通知 watcher-->相关联的组件重新渲染。
实际例子的体现
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。并且对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property
处理对象时
var vm = new Vue({ data:{ a:1}}) // `vm.a` 是响应式的
vm.b = 2 // `vm.b` 是非响应式的
针对方法
Vue.set(vm.someObject, 'b', 2) //全局方法
this.$set(this.someObject,'b',2) //实例方法
处理数组时
Vue 不能检测以下数组的变动:
第一种
利用索引直接设置一个数组项如: vm.items[indexOfItem] = newValue
第二种
修改数组的长度如: vm.items.length= newLength
针对方法
第一种
Vue.set(vm.items, indexOfItem, newValue) //全局方法
vm.items.splice(indexOfItem, 1, newValue) //实例方法
vm.$set(vm.items, indexOfItem, newValue)
第二种
vm.items.splice(newLength)
声明响应式 property
var vm = new Vue({
data: {
// 声明 message 为一个空值字符串
message: ''
},
template: '<div>{{ message }}</div>'
})
// 之后设置 `message`
vm.message = 'Hello!'
一个先声明占位的思想-->即使undefind也可以
在代码可维护性方面也有一点重要的考虑:data 对象就像组件状态的结构 (schema)。提前声明所有的响应式 property,可以让组件代码在未来修改或给其他开发人员阅读时更易于理解。
Vue2.0 总结
- 基于Object.defineProperty,不具备监听数组的能力,需要重新定义数组的原型来达到响应式。
- Object.defineProperty 无法检测到对象属性的添加和删除 。
- 由于Vue会在初始化实例时对属性执行getter/setter转化,所有属性必须在data对象上存在才能让Vue将它转换为响应式。
- 深度监听需要一次性递归,对性能影响比较大。
Vue 3.0 响应式原理--Proxy
当把一个普通的 JavaScript 对象作为 data 选项传给应用或组件实例的时候,Vue 会使用带有 getter 和 setter 的处理程序 遍历其所有 property 并将其转换为 Proxy-MDN
-
当某个值发生变化时进行检测不再需要-->Proxy 允许Vue拦截并且 -
跟踪更改它的函数:在 proxy 中的 getter 中执行此操作,称为 effect
-
触发函数更新最终值:proxy 中的 setter 中进行该操作,名为 trigger
实际例子的体现
Vue3.0 总结
- 基于Proxy和Reflect,可以原生监听数组,可以监听对象属性的添加和删除。
- 不需要一次性遍历data的属性,可以显著提高性能。
- Proxy是ES6新增的属性。