isRef
判断是不是 ref
单元测试
// ref.spec.ts
describe("ref", () => {
it("isRef", () => {
const a = ref(1);
const b = reactive({ foo: 1 });
expect(isRef(a)).toBe(true);
expect(isRef(1)).toBe(false);
expect(isRef(b)).toBe(false);
});
})
代码实现
// ref.ts
class RefImpl {
public __v_isRef = tue;
...
}
export function isRef(ref) {
return !!ref.__v_isRef;
}
这里返回值加上两个感叹号是为了如果参数不是一个 ref,那么 ref.__v_isRef 是 undefined。所以要变成boolean 值
unRef
如果是 ref,返回 .value,否则返回本身
单元测试
// ref.spec.ts
describe("ref", () => {
it("unRef", () => {
const a = ref(1);
expect(unRef(a)).toBe(1);
expect(unRef(1)).toBe(1);
});
})
代码实现
// ref.ts
export function unRef(ref) {
return isRef(ref) ? ref.value : ref;
}
proxyRef
在 vue3 的 template 模板中使用 ref,不需要调用 .vue,就是用到了 proxyRef
// ref.spec.ts
describe("ref", () => {
it("proxyRefs", () => {
const user = {
age: ref(10),
name: "5c24",
};
const proxyUser = proxyRefs(user);
expect(user.age.value).toBe(10);
expect(proxyUser.age).toBe(10);
expect(proxyUser.name).toBe("5c24");
proxyUser.age = 20;
expect(proxyUser.age).toBe(20);
expect(user.age.value).toBe(20);
proxyUser.age = ref(10);
expect(proxyUser.age).toBe(10);
expect(user.age.value).toBe(10);
});
})
从单元测试可以知道当用 proxyRefs 包裹的对象 proxyUser 可以直接 .age 获得值,而 user 获取 age 值需要 user.age.value
当 proxyUser 的 age 值赋了一个不管是不是 ref 的值, user.age 的值都会跟着变
代码实现
// ref.ts
export function proxyRefs(objectWithRef) {
return new Proxy(objectWithRef, {
get(target, key) {
// 如果访问的是 ref 类型 返回 .value,如果不是 ref ,返回本身的值
return unRef(Reflect.get(target, key));
},
set(target, key, value) {
if(isRef(target[key]) && !isRef(value)) {
// 如果新给值不是一个 ref 类型,把当前对象需要赋值的属性为 ref 的 .value 改掉
return (target[key].value = value);
} else {
// 如果新值是一个 ref,直接替换
return Reflect.set(target, key, value);
}
},
})
}