118 lines
2.3 KiB
JavaScript
118 lines
2.3 KiB
JavaScript
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
|