【mini-vue】- 实现proxyRefs

59 阅读2分钟

实现 proxyRefs

主要思路

proxyRefs: 在vue3中,当return的值里面还有 ref 类型数据的时候,此时可以不经过.value 就可以直接获取到里面的值。(具体例子看单测)

实现get逻辑:很简单,判断当前对象属性值是否是ref类型,如果是直接返回ref.value(那么在外面就不用通过.value 去取值了)。如果不是ref类型,那么更简单了,说明要么是reactive类型要么是基本数据类型,直接返回本身即可。

实现set逻辑:如果不需要通过.value去赋值的话,那么也是直接在内部通过target[key].value = value就好了。 但这里需要考虑外部传进来的新值是否是ref类型,如果不是的话,可以使用 target[key].value = value 进行赋值。如果外部传进来的值是ref类型,那么直接赋值即可就不需要.value啦!(也就是 target[key] = value)

代码

export function proxyRefs(objectWithRefs) {
  return new Proxy(objectWithRefs, {
    get(target, key) {
      // get : 如果是 ref 那么返回ref.value 否则 返回 value本身(基本数据类型)
      return unRef(Reflect.get(target, key))
    },
    set(target, key, value) {
      // 判断 当前对象属性值 和 传入的值 是否是ref
      if (isRef(target[key]) && !isRef(value)) {
        return (target[key].value = value)
      } else {
        return Reflect.set(target, key, value)
      }
    }
  })
}
// isRef  和 unRef
export function isRef(ref) {
  return !!ref._v_isRef  // 如果是ref那么自然会返回自己身上的_v_isRef属性值,如果不是的话那么会返回undefined 为了返回布尔值在前面加上!!
}

// unRef: 我愿称之为,蜕去外壳,直接返回内部值
export function unRef(ref) {  
  return isRef(ref) ? ref.value : ref // 如果是ref 返回 ref.value 否则 返回 value本身
}

单元测试

it("proxyRefs", () => {
    const user = {
      age: ref(1),
      name: "zhangsan",
    }
    const proxyUser = proxyRefs(user)

    //  get 
    expect(user.age.value).toBe(1)
    expect(proxyUser.name).toBe("zhangsan")
    expect(proxyUser.age).toBe(1)  // expect(proxyUser.age.value).toBe(1)  省去了value的操作
    


    // set  
    proxyUser.age = 20
    expect(proxyUser.age).toBe(20)
    expect(user.age.value).toBe(20)

    proxyUser.age = ref(20)
    expect(proxyUser.age).toBe(20)
    expect(user.age.value).toBe(20)

  })