vue 3 响应式基基基础

60 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情

Proxy

代理对象,新的api,就像是中介一样,这个东西确实可以帮你做很多事,当前也需要消耗一点点性能,但是这个中介是不可或缺的 首先有如下对象

 let obj = {
    name: "石头",
    list: [1, 2, 3]
  }

然后将对象交给一个叫reactive的方法,就可以得到一个响应式的对象,这个方法里就是使用es6新特性proxy,这个类接收两个参数,第一个是目标对象,也可以叫源对象,第二个是代理规则,代理的属性有很多,这里主要用的就是读和写还有删除,首先拦截一下get方法,在get方法里trak一下,相应数据结构为map结构,使用这个key当key,然后存起来,等改这个对象的时候直接trigger一下,触发对应的更新函数

set 里有个小细节,就是当改变了对象属性值发生变化或者有新增属性时才触发更新,因为数组那个东西push一个东西时不光加了一个元素,长度属性也会变,从而导致触发两次更新,当是没关系,这个更新最后只会执行一次,再他里面处理了 设置新的属性的时候也要尝试一下代理。因为这个属性值可能是一个对象 get 里有个小细节,就是获取属性值时,这个值可能又是一个对象,但不一定是代理对象,所以要尝试代理一下这个对象,是对象就代理一下,不是就算了

  const handler = {
    set (taget, key, value, receiver) {
        trigger()
      return Reflect.set(taget, key, value, receiver)
    },
    get (taget, key, receiver) {
      return reactive(Reflect.get(taget, key, receiver))
    },

    deleteProperty (target, key) {
      return Reflect.defineProperty(target, key)
    }

  }
  function reactive (taget) {
    if (!isObject(taget)) {
      return taget
    }
    let observeb = new Proxy(taget, handler)
    return observeb
  }

如下小案例 每次处理一个代理对象都要缓存一下,避免同一个对象被代理多次。然后假如说赋值给代理对象一个属性,而这个值是一个已经代理的对象,那么好,直接返回这个对象。

  // 存代理对象
  const toProxy = new WeakMap()
  // 存代理前的对象
  const toRow = new WeakMap()
  function trigger () {
    console.log('shi图更新')
  }

  function isObject (taget) {
    return typeof taget === 'object' && taget !== null
  }
  const handler = {
    set (taget, key, value, receiver) {
      trigger()
      return Reflect.set(taget, key, reactive(value), receiver)
    },
    get (taget, key, receiver) {
      return reactive(Reflect.get(taget, key, receiver))
    },

    deleteProperty (target, key) {
      return Reflect.defineProperty(target, key)
    }

  }
  function reactive (taget) {
    if (!isObject(taget)) {
      return taget
    }
    // 如果这个值代理过了,直接走缓存
    const proxyed = toProxy.get(taget)
    if (proxyed) {
      return proxyed
    }
    // 如果这个值就是代理对象,直接返回好了
    if (toRow.has(taget)) {
      console.log('zoule')
      return taget
    }
    let observeb = new Proxy(taget, handler)
    toProxy.set(taget, observeb)
    toRow.set(observeb, taget)
    return observeb
  }
  let obj = {
    name: "石头",
    list: [1, 2, 3]
  }
  let r = reactive(obj)
  let p = reactive(obj.list)
  r.b = p;