跳转到内容
aswind7
GitHub
Blog

简易的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: