Appearance
两个版本响应式
Vue2
监听对象
通过Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)
对象中后追加的属性,Vue 默认不做响应式处理
如需给后添加的属性做响应式,请使用如下 API:
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
js
let data = {
name: "Tom",
age: 18,
score: {
math: 12,
english: 20,
},
};
//创建一个监视的实例对象,用于监视data中属性的变化
let obs = new Observer(data);
//准备一个vm实例对象
let vm = {};
vm._data = obs;
function Observer(obj) {
let keys = Object.keys(obj);
for (let k of keys) {
Object.defineProperty(this, k, {
get() {
return obj[k];
},
set(value) {
obj[k] = value;
},
});
if (typeof obj[k] === "object" && obj[k] !== null) {
obj[k] = new Observer(obj[k]);
}
}
}
监听数组
通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
在 Vue 修改数组中的某个元素一定要用如下方法
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
Vue.set()
或vm.$set()
注意
vue 会监视 data 中所有层次的数据;Vue.set()
和 vm.$set()
不能给 vm 或 vm 的根数据对象 添加属性
Vue3
Proxy(代理)
通过Proxy
拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等
js
let data = {
name: "Tom",
age: 49,
};
let p = new Proxy(data, {
get(target, propName) {
return target[propName];
},
// 修改和新增
set(target, propName, value) {
target[propName] = value;
},
deleteProperty(target, propName) {
//deleteProperty必须返回一个布尔值表示是否删除成功
return delete target[propName]; // delete执行返回true
},
});
Reflect(反射)
通过 Reflect(反射): 对源对象的属性进行操作
js
let data = {
name: "Tom",
age: 49,
};
let p = new Proxy(data, {
get(target, propName) {
return Reflect.get(target, propName);
},
// 修改和新增
set(target, propName, value) {
Reflect.set(target, propName, value);
},
deleteProperty(target, propName) {
//deleteProperty必须返回一个布尔值表示是否删除成功
return Reflect.deleteProperty(target, propName);
},
});
reactive 简易实现
js
// 判断是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 数据
let data = {
name: "Tom",
age: 49,
score: {
math: 20,
art: 39,
},
};
function reactive(target) {
if (!isObject(target)) return target;
const handler = {
get(target, propName) {
console.log(`获取对象属性${propName}值`);
const result = Reflect.get(target, propName);
if (isObject(result)) {
// 值如果是引用类型, 递归为其每个内部元素添加代理
return reactive(result);
}
return result;
},
set(target, propName, value) {
console.log(`设置对象属性${propName}值`);
return Reflect.set(target, propName, value);
},
deleteProperty(target, propName) {
console.log(`删除对象属性${propName}值`);
return Reflect.deleteProperty(target, propName);
},
};
return new Proxy(target, handler);
}
const r = reactive(data);