简易的Vue3核心实现
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// WeakMap常用于存储只有当key所引用的对象存在时(没有被回收)才有价值的消息,十分贴合双向绑定场景
const bucket = new WeakMap(); // 存储副作用函数
let activeEffect; // 用一个全局变量处理被注册的函数
const tempObj = {}; // 临时对象,用于操作
const data = { text: "hello world" }; // 响应数据源
// 用于清除依赖
function cleanup(effectFn) {
for (let i = 0; i < effectFn.deps.length; i++) {
const deps = effectFn.deps[i];
deps.delete(effectFn);
}
effectFn.deps.length = 0;
}
// 处理依赖函数
function effect(fn) {
debugger
const effectFn = () => {
cleanup(effectFn);
activeEffect = effectFn;
fn();
};
effectFn.deps = [];
effectFn();
}
// 在get时拦截函数调用track函数追踪变化
function track(target, key) {
debugger
if (!activeEffect) return; //
let depsMap = bucket.get(target);
if (!depsMap) {
bucket.set(target, (depsMap = new Map()));
}
let deps = depsMap.get(key);
if (!deps) {
depsMap.set(key, (deps = new Set()));
}
deps.add(activeEffect);
activeEffect.deps.push(deps);
}
// 在set拦截函数内调用trigger来触发变化
function trigger(target, key) {
const depsMap = bucket.get(target);
if (!depsMap) return;
const effects = depsMap.get(key);
const effectsToRun = new Set(effects);
console.log('effectsToRun: ', effectsToRun);
effectsToRun.forEach(effectFn => effectFn());
// effects && effects.forEach(fn => fn());
}
const obj = new Proxy(data, {
// 拦截读取操作
get(target, key) {
if (!activeEffect) return; //
console.log("get -> key", key);
track(target, key);
return target[key];
},
// 拦截设置操作
set(target, key, newValue) {
console.log("set -> key: newValue", key, newValue);
target[key] = newValue;
trigger(target, key);
},
});
effect(() => {
debugger
tempObj.text = obj.text;
console.log("tempObj.text :>> ", tempObj.text);
});
setTimeout(() => {
obj.text = "hi vue3";
}, 1000);
setTimeout(() => {
obj.text = "hi vue34";
}, 2000);
</script>
</body>
</html>
Tags: