const arrayProto = Array.prototype;
function defArrayFunc(obj, func, namespace, vm) {
Object.defineProperty(obj, func, {
configurable: true,
enumerable: true, // 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中
// 触发枚举属性中的属性或者触发数组相关事件后会被捕获到
value(...args) { // args是操作数组时的添加/删除的对象/其他类型的值的数组,例如push(2), args为[2]
let original = arrayProto[func]; // 获取数组原型中对应func的函数,例如func为push时,original为function push(){}
const result = original.apply(this, args); // 调用original函数,this是代理的数组
console.log(getNameSpace(namespace, ""));
return result;
}
})
}
function proxyArr(vm, arr, namespace) {
let obj = {
eleType: "Array",
toString() {
let result = "";
for (let i = 0; i < arr.length; i++) {
result += arr[i] + ", ";
}
return result.substring(0, result.length - 2);
},
push() {
},
pop() {
},
shift() {
},
unshift() {
}
};
defArrayFunc.call(vm, obj, "push", namespace, vm);
defArrayFunc.call(vm, obj, "pop", namespace, vm);
defArrayFunc.call(vm, obj, "shift", namespace, vm);
defArrayFunc.call(vm, obj, "unshift", namespace, vm);
arr.__proto__ = obj; // 这个加不加不影响
return arr;
}
function constructObjectProxy(vm, obj, namespace) {
// 通过es6 Proxy实现
// let proxyObj = new Proxy(obj, {
// get(target, p, receiver) {
// console.log("=")
// return target[p];
// },
// set(target, p, value, receiver) {
// console.log("=")
// target[p] = value;
// }
// });
//
// return proxyObj;
// 下面通过Object.defineProperty实现
let proxyObj = {};
for (let prop in obj) {
Object.defineProperty(proxyObj, prop, {
configurable: true,
get() {
return obj[prop];
},
set(v) {
console.log(getNameSpace(namespace, prop));
obj[prop] = v;
}
});
// 实现Vue中通过this.xxx来使用data中的属性
Object.defineProperty(vm, prop, {
configurable: true,
get() {
return obj[prop];
},
set(v) {
console.log(getNameSpace(namespace, prop));
obj[prop] = v;
}
});
if (obj[prop] instanceof Object) {
proxyObj[prop] = constructProxy(vm, obj[prop], getNameSpace(namespace, prop))
}
}
return proxyObj;
}
/**
* 我们要知道Vue的data上哪个属性修改,我们才能对页面上的内容进行更新
* 所以我们需要先捕获修改的这个事件,使用代理的方式来实现监听属性修改
* 这里使用Object.defineProperty
* @param vm
* @param obj
* @param namespace
*/
export function constructProxy(vm, obj, namespace) {// vm表示Vue对象,obj表示要代理的对象
// 递归
let proxyObj = null;
if (obj instanceof Array) { // 判断这个对象是否为数组
proxyObj = new Array(obj.length);
for (let i = 0; i < obj.length; i++) {
proxyObj[i] = constructProxy(vm, obj[i], namespace);
}
proxyObj = proxyArr(vm, obj, namespace);
} else if (obj instanceof Object) { // 判断这个对象是否为对象
// 构造代理对象
proxyObj = constructObjectProxy(vm, obj, namespace);
} else {
throw new Error("error");
}
return proxyObj;
}
function getNameSpace(nowNameSpace, nowProp) {
if (nowNameSpace === null || nowNameSpace === "") {
return nowProp;
} else if (nowProp == null || nowProp === "") {
return nowNameSpace;
} else {
return nowNameSpace + "." + nowProp;
}
}
MVVM原理(代理data)
猜你喜欢
转载自blog.csdn.net/qq1123642601/article/details/104419999
今日推荐
周排行