Vue3如何给reactive对象赋值,试试reactiveRef

16 阅读1分钟

实现 reactiveRef 的方法

以下是实现 reactiveRef 的方法,满足你的需求:

import { ref, isRef } from 'vue';

function reactiveRef(initialValue) {
  const internalRef = ref(initialValue);

  return new Proxy(internalRef, {
    get(target, prop, receiver) {
      // 直接访问实例时返回 .value 的值
      if (prop === Symbol.toPrimitive || prop === 'valueOf') {
        return () => target.value;
      }
      if (prop === 'toString') {
        return () => target.value.toString();
      }

      // 访问 .value 属性时返回原始值
      if (prop === 'value') {
        return target.value;
      }

      // 如果当前内容是对象,则代理到内部
      const v = internalRef.value;
      if (v && typeof v === 'object') return v[prop]

      // 保留 ref 的其他属性(如 .effect)
      return Reflect.get(target, prop, receiver);
    },
    set(target, prop, value, receiver) {
      // 设置 .value 属性时修改原始值
      if (prop === 'value') {
        target.value = value;
        return true;
      }

      // 否则给内部对象赋值
      if (typeof internalRef.value === 'object' && internalRef.value !== null) {
        internalRef.value[prop] = value;
        return true
      }

      // 其他属性直接设置
      return Reflect.set(target, prop, value, receiver);
    },

    // 直接调用对象(如reactiveRef(1)())时返回internalRef.value
    apply(target, thisArg, argumentsList) {
      return internalRef.value
    }
  });
}

// 使用示例
const count = reactiveRef(0)
console.log(count.value) // 0
count.value = 10;
console.log(count.value) // 10

// 如果value默认是一个对象
const state = reactiveRef({a: 1, b: 2});
console.log(state.a) // 1
state.a = 12
console.log(state.a) // 12

// 依然可以用state.value = {...}替换整个对象
state.value = {a: 9, b: 9}
console.log(state.a)
console.log(state.value.b)

特性说明

  • 直接访问值:当直接访问 count 时,会自动返回 .value 的值
  • 强制使用 .value 设置:必须通过 count.value = newValue 修改值
  • 保留完整功能
    • 仍可通过 count.value 访问原始 ref 对象
    • 保留 isRef 检测等原始功能
    • 响应式系统正常工作

注意事项

  • 不要直接给 count 变量赋值(如 count = 5),这会改变变量指向的对象
  • 深层次对象仍需保持响应式(与普通 ref 行为一致)
  • 在模板中使用时仍会自动解包,与普通 ref 行为一致

这个实现通过 Proxy 拦截了属性的访问和设置,在保持 Vue 响应式系统完整性的同时,修改了值的访问方式。