1 响应式原理
vue响应式也叫作数据双向绑定
MVVM模型 (Model-Viem-ViewModel)
- DOM listeners:实现了页面与数据的绑定,当页面操作数据的时候 DOM 和 Model 也会发生相应的变化
- Data Bindings: 实现了数据与页面的绑定,当数据发生变化的时候会自动渲染页面
2 vue2 数据监听
2.1 实现原理
vue实现数据响应式,是通过object.defineProperty()对数据劫持侦测数据变化,发布订阅模式进行依赖收集与视图更新。
object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
2.2 object.defineProperty()对数据的监听
const obj = { name: "one", age: 18 } Object.keys(obj).forEach(key => { let value = obj[key] Object.defineProperty(obj, key, { get: function() { console.log(`监听到obj对象的${key}属性被访问了`) return value }, set: function(newValue) { console.log(`监听到obj对象的${key}属性被设置值`) value = newValue } }) }) obj.name = "two" obj.age = 20 console.log(obj.name) console.log(obj.age) obj.height = 1.88
复制
2.3 object.defineProperty()缺陷
1.defineProperty只能监听某个属性,不能对全对象监听 对一个对象的监听需使用foreach、闭包等技术
2. defineproperty不能监听到对象的添加删除属性操作
需要开发者主动调用相应的方法去更新 :Vue.set(),Vue.delete
2.defineproperty不能监听数组的添加删除操作
直接使用索引 index 设置数组项时,不会被vue检测到
vue2.0使用数组重写的方法实现了数组的响应,7个方法分别为
push();
pop();
shift();
unshift();
splice();
sort();
reverse()
3 vue3 数据监听
3.1 原理
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义。之后的操作都是直接对Proxy的操作,而不是原有的对象
const p = new Proxy(target, handler)
target
要使用 Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为。
handler对象的方法【MDN】(13个捕获器 trap)
3.2 代码
const obj = { name: 'one', age: 18, }; const objProxy = new Proxy(obj, { // 获取值时的捕获器 get: function (target, key) { console.log(`监听到对象的${key}属性被访问了`, target); return target[key]; }, // 设置值时的捕获器 set: function (target, key, newValue) { target[key] = newValue; console.log(`监听到对象的${key}属性被设置值`, target); }, // 监听in的捕获器 has: function (target, key) { console.log(`监听到对象的${key}属性in操作`, target); return key in target; }, // 监听delete的捕获器 deleteProperty: function (target, key) { delete target[key]; console.log(`监听到对象的${key}属性delete操作`, target); }, }); console.log(objProxy.name); console.log(objProxy.age); objProxy.name = 'two'; objProxy.age = 20; // in操作符 console.log('name' in objProxy); // delete操作 delete objProxy.name; console.log(obj.name); console.log(obj.age);
复制
执行结果