2024-06-01 04:29:31 +08:00

118 lines
2.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const targetMap = new WeakMap() // 用原始对象作为key依赖映射作为value
let activeEffect = null // 保存当前的需要订阅通知的effect
function track(target, key) {
if(activeEffect) {
let depsMap = targetMap.get(target)
if(!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if(!dep){
depsMap.set(key, (dep=new Set()))
}
dep.add(activeEffect) // 将efect添加进通知set
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if(!depsMap) return
const deps = depsMap.get(key)
deps.forEach(effect => {
effect()
});
}
function reactive(target){
const hander = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
return result
},
set(target, key, value, receiver) {
let oldValue = target[key]
let result = Reflect.set(target, key, value, receiver)
if (oldValue !== value){
trigger(target, key)
}
return result
}
}
return new Proxy(target, hander)
}
// 创建ref为基本数据类型赋予响应式功能
function ref(raw) {
const r = {
get value(){
track(r, 'value')
return raw
},
set value(newVal){
raw = newVal
trigger(r, 'value')
}
}
return r
}
function effect(effect){
activeEffect = effect
activeEffect()
activeEffect = null
}
function computed(getter){
let result = ref()
effect(()=>(result.value = getter()))
return result
}
function watch(source, callback) {
let getter;
if (typeof source === 'function') {
getter = source;
} else {
getter = () => source.value;
}
let oldValue, newValue;
const effectFn = () => {
newValue = getter();
if(oldValue !== undefined) callback(newValue, oldValue); // watch第一次不需要执行
oldValue = newValue;
};
effect(effectFn);
}
// 测试用例
const product = reactive({ price: 5, quantity: 2 });
watch(
() => product.price,
(newPrice, oldPrice) => {
console.log(`Price changed from ${oldPrice} to ${newPrice}`);
}
);
const total = ref(1)
watch(total, (newVal, oldVal)=>{
console.log(`Total changed from ${oldVal} to ${newVal}`);
})
product.price = 10; // 应触发 watch 回调并打印 "Price changed from 5 to 10"
product.price = 100
total.value = 2
total.value = 3