vue 模拟set del 方法
上篇主要对数组格式数据进行响应式处理,vue 有set 和del 方法可以对数组和对象进行修改和删除。代码如下:
数组类型的数据修改和删除时候,只需要调用splice方法就可以,在上一篇数组响应是在get方法中属性为数组格式时进行依赖的注入,现在在每个属性都注入,这样调用set方法时候,才能在_ob_属性中去触发依赖函数的更新。
import Dep from "./dep";
import { hasProto, def,hasOwn } from "./utils/index";
import { arrayMethods } from "./array";
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
const NO_INIITIAL_VALUE = {};
function defineReactive(obj, key, val, shallow) {
console.log(obj,key,val,'kkkkkddd')
// 获取当前属性有没有自定义方法;
let property = Object.getOwnPropertyDescriptor(obj, key);
// 判断当前属性有没有自定义get set 方法
let getter = property && property.get;
let setter = property && property.set;
// 没有val值,去obj里面的
if (
(!getter || setter) &&
(val === NO_INIITIAL_VALUE || arguments.length == 2)
) {
val = obj[key];
}
const dep = new Dep(); // 持有一个 Dep 对象,用来保存所有依赖于该变量的 Watcher
// 如果有深度对象,则深度监听
let childOb = !shallow && observe(val, false);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function () {
//添加依赖函数
if (Dep.target) {
// dep.addSub(Dep.target);
dep.depend();
if (childOb) {
if (Array.isArray(val)) {
// 如果当前值是数组,给数组生成的observer.dev添加依赖函数
childOb.dep.depend();
//循环数组,对嵌套数组进行依赖收集
dependArray(val)
}
/******新增 *************************/
//给每个属性都添加一个依赖函数,这样对象通过set新增一个属性后就可以去触发更新
childOb.dep.depend();
}
/************************************/
}
//如果有自定义方法则调用
let value = getter ? getter.call(obj) : val;
return value;
},
set: function (newVal) {
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
// 如果对一个对象整体赋值后,再修改对象属性也没有响应效果,在set也监听下
childOb = !shallow && observe(newVal, false);
//执行依赖当前属性的依赖函数
dep.notify();
},
});
}
export class Observer {
// shallow 属性判断是否需要深度监听
constructor(data, shallow = false) {
this.dep = new Dep(); // 新增dep
def(data, "__ob__", this); // 每个数据都新增_ob_属性绑定当前Observer实例
if (Array.isArray(data)) {
// 判断当前值是否是数组类型,是否有__proto__属性,将重写的方法指向原型
if (hasProto) {
data.__proto__ = arrayMethods;
} else {
for (let i = 0, l = arrayKeys.length; i < l; i++) {
const key = arrayKeys[i];
def(data, key, arrayMethods[key]);
}
}
//添加对数组里面每一个值进行响应式监听
this.observeArray(data)
} else {
this.walk(data, shallow);
}
}
walk(data, shallow) {
let keys = Object.keys(data);
for (let key of keys) {
defineReactive(data, key, NO_INIITIAL_VALUE, shallow);
}
}
// 循环数组,对数组里面值进行监听
observeArray(data){
for(let i=0;i<data.length;i++){
observe(data[i])
}
}
}
export function observe(data, shallow = false) {
if (data !== null && typeof data === "object") {
return new Observer(...arguments);
} else {
return false;
}
}
//多层数组嵌套响应
function dependArray(value) {
for (let e, i = 0, l = value.length; i < l; i++) {
e = value[i];
if (Array.isArray(e)) {
e && e.__ob__ && e.__ob__.dep.depend();
dependArray(e); // 递归进行
}
}
}
// set 方法
export function set(target,key,val){
// 如果是数组类型
if(Array.isArray(target)){
target.length = Math.max(target.length,key)
target.splice(key,1,val)
return val
}
//如果是对象类型 修改target自身的属性
if(target[key] && !(key in Object.prototype)){
Object.prototype = val;
return val
}
let ob = target.__ob__;
// 前面数据响应式每个属性都添加了_ob_属性,如果没有说明target不是响应式的数据
if(!ob){
target[key] = val;
return val
}
// 如果是响应式数据,则将新增的值变为响应式
defineReactive(target, key, val,false);
// 让依赖的方法更新
ob.dep.notify()
}
//delete 方法
export function del(target,key){
// 如果是数组类型
if(Array.isArray(target)){
target.length = Math.max(target.length,key)
target.splice(key,1)
return
}
//如果target是对象类型
const ob = target.__ob__;
if (!hasOwn(target, key)) {
return;
}
delete target[key];
if (!ob) {
return;
}
ob.dep.notify();
}
import { observe,set,del } from "./reactive";
import { Watcher } from "./watcher";
const data = {
test2: {
dd: "aa",
},
arr: ["a",{test:'oo'},['a']],
};
const recursion = () => {
console.log(data.test2.hh);
};
const updateArr = () => {
data.arr.map((item) => console.log(item));
};
observe(data);
// 深度响应
new Watcher(recursion);
// 数组方法响应
new Watcher(updateArr);
//数组set 方法
//set(data.arr,4,'add')
// 对象set 方法
//set(data.test2,'hh','ppp')
//数组删除
//del(data.arr,0)
//对象删除方法
del(data.test2,'dd')

浙公网安备 33010602011771号