vue中 数据驱动视图更新,是通过数据监听实现,也就是响应式

在vue2中通过 Object.defineProperty实现响应式,实现思路如下

  • 监听对象,深度监听通过递归
  • 数组监听通过重写数组原型方法
// 重新定义数组原型
  const oldArrayPrototty = Array.prototype;
  // 创建新对象,原型指向oldArrayPrototty,再扩展新的方法不会影响原型
  const arrProto = Object.create(oldArrayPrototty);
  ['push', 'pop', 'shift', 'unshift', 'splice', 'join'].forEach(methodName => {
    arrProto[methodName] = function() {
      console.log('数组更新');
      return oldArrayPrototty[methodName].call(this, ...arguments);
      // Array.prototype[methodName].call(this, ...arguments); 调用数组的原型方法
    }
  })
 function defineReactive(target, key, value) {
    observer(value);// 深度监听
    Object.defineProperty(target, key, {
      get() { return value },
      set(newValue) {
        if (newValue !== value) {
          value = newValue;
          observer(newValue);// 深度监听
          console.log('数据更新');
        }
      }
    })
 }
 function observer(target) {
  if (typeof target !== 'object' || target == null)  return target;
  // 数组监听处理
  if (Array.isArray(target)) {
    target.__proto__ = arrProto;
  }
  for(let key in target) {
    // 过滤原型属性
    if (target.hasOwnProperty(key)) {
      defineReactive(target, key, target[key]);
    }
  }
 }

let data = { arr: [100, 200, 300], name: '张三'};
observer(data);
data.arr.pop();
data.name = '李四';

 

vue3 通过 proxy 响应式

function reactive(target) {
  if (typeof target !== 'object' || target === null) {
    return target;
  }
  const proxyConfig = {
    get(target, key, receiver) {
      // 只处理本身属性,不处理原型属性
      const ownkeys = Reflect.ownKeys(target);
      if (ownkeys.includes(key)) {
        // 监听
        console.log('get', key);
      }
      const result = Reflect.get(target, key, receiver);
      // 深度监听 - 性能提升,在get的时候才递归
      return reactive(result);
    },
    set(target, key, val, receiver){
      // 重复数据不处理
      if (val === target[key]) {
        return true;
      }
      const result = Reflect.set(target, key, val, receiver);
      const ownkeys = Reflect.ownKeys(target);
      if (ownkeys.includes(key)) {
        console.log('已有的key', key);
      } else {
        console.log('新增的key', key);
      }
      return result;
    },// 删除
    deleteProperty(target, key, val) {
      const result = Reflect.deleteProperty(target, key);
      console.log('delete', key);
      return result;
    }
  }
  return new Proxy(target, proxyConfig);;
}

 

posted on 2023-05-24 14:50  浅唱年华1920  阅读(13)  评论(0编辑  收藏  举报