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);
执行结果