实现 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 响应式系统完整性的同时,修改了值的访问方式。