当前位置: 首页 > article >正文

前端从零开始写一个简单的响应式

写一个简单的响应式。
不是vue的源码更多的是一个理解。
首先需要遍历对象,为对象的每个属性设置settergetter

function observer(obj) {
    const vm = {};
    for (const prop in obj) {
        if (Object.hasOwnProperty.call(obj, prop)) {
            const dep = new Dep();
            Object.defineProperty(vm, prop, {
                get() {
                    dep.depend();
                    return data[prop];
                },
                set(val) {
                    data[prop] = val;
                    dep.notify();
                }
            })
        }
    }
    return vm;
}

收集依赖通过Dep实例进行收集,并且收集的是Watcher实例。
Dep

class Dep {
    deps = [];
    notify() {
        const deps = this.deps;
        this.deps = [];
        for (let i = 0; i < deps.length; i++) {
            const watcher = deps[i];
            schedule.push(watcher);
        }
        schedule.nextTick();
    }
    depend() {
        watcher && this.deps.push(watcher);
    }
}

Watcher

class Watcher {
    constructor(data, prop, cb) {
        this.data = data;
        this.prop = prop;
        this.cb = cb;
        this.value = this.get();
    }
    get() {
        watcher = this;
        let value = this.data[this.prop];
        watcher = undefined;
        return value;
    }
    update() {
        const oldValue = this.value;
        this.value = this.get();
        this.cb(this.value, oldValue);
    }
}

watcher实例的执行是异步任务,并且微任务的优先级更高。需要调度器Schedule

class Schedule {
  _task = new Set();

    push(watcher) {
        this._task.add(watcher);
    }

    _run() {
        const task = this._task;
        this._task = new Set();
        for (const watcher of task) {
            watcher.update();
        }
    }

    nextTick() {
        Promise.resolve().then(this._run.bind(this));
    }
}

完整案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <div id="first">1</div>

    <script>
        let watcher = null;

        class Schedule {
            _task = new Set();

            push(watcher) {
                this._task.add(watcher);
            }

            _run() {
                const task = this._task;
                this._task = new Set();
                for (const watcher of task) {
                    watcher.update();
                }
            }

            nextTick() {
                Promise.resolve().then(this._run.bind(this));
            }

        }
        const schedule = new Schedule();
        class Dep {
            deps = [];
            notify() {
                const deps = this.deps;
                this.deps = [];
                for (let i = 0; i < deps.length; i++) {
                    const watcher = deps[i];
                    schedule.push(watcher);
                }
                schedule.nextTick();
            }
            depend() {
                watcher && this.deps.push(watcher);
            }
        }

        class Watcher {
            constructor(data, prop, cb) {
                this.data = data;
                this.prop = prop;
                this.cb = cb;
                this.value = this.get();
            }
            get() {
                watcher = this;
                let value = this.data[this.prop];
                watcher = undefined;
                return value;
            }
            update() {
                const oldValue = this.value;
                this.value = this.get();
                this.cb(this.value, oldValue);
            }
        }




        const data = { count: 1 };

        function observer(obj) {
            const vm = {};
            for (const prop in obj) {
                if (Object.hasOwnProperty.call(obj, prop)) {
                    const dep = new Dep();
                    Object.defineProperty(vm, prop, {
                        get() {
                            dep.depend();
                            return data[prop];
                        },
                        set(val) {
                            data[prop] = val;
                            dep.notify();
                        }
                    })
                }
            }
            return vm;
        }
        const observerData = observer(data);
        const firstDOM = document.getElementById("first");
        const oWatcher = new Watcher(observerData, "count", function (val, oldVal) {
            console.log(val, oldVal);
            firstDOM.innerHTML = val;
        })
        firstDOM.onclick = function () {
            observerData.count++;
            observerData.count++;
            observerData.count++;
        }

    </script>

</body>

</html>

代码是提供一个思路,有些函数并不会进行参数兼容。 响应式的代码主要是看个意思,具体什么深度递归设置 Dep,处理循环引用这些问题不是没考虑到,因为这些代码仅仅提供给大家参考学习。 如果确实有需求的,制作一个完整的 MVVM,可以直接去看 vue 的源码。

在最近几天我把一些常见的前端手写题进行了整理,也希望能有更多的前端爱好者一起来学习和维护。

github地址 :Front-end-handwriting

我同时也将自己21年写的一个vue的音乐项目整理出来放到github上了,有兴趣的朋友可以看一下。

因为你之前努力过了,才会有今天的你。


http://www.kler.cn/a/7077.html

相关文章:

  • Windows图形界面(GUI)-QT-C/C++ - Qt图形绘制详解
  • 机器学习(1):线性回归概念
  • IOS界面传值-OC
  • Qt WORD/PDF(五)使用Json一键填充Word表格
  • Spring Boot 2 学习全攻略
  • 小结:华为交换机常用的操作指令
  • 【软考五】数据库(做题)
  • Flutter-Scaffold组件
  • 软考试题难不难?怎么复习备考?
  • P3975 [TJOI2015]弦论(SAM DAG、parent树上dp计算不同子串数 递归输出字典序第k大子串)
  • 前后台协议联调拦截器
  • 快速玩转 CNStack 2.0 流量防护
  • 逍遥自在学C语言 | 逻辑运算符
  • 学习HCIP的day.2
  • vue echarts 画饼图
  • 704. 二分查找
  • vue3项目快速开发模板
  • 论文阅读《LargeKernel3D: Scaling up Kernels in 3D Sparse CNNs》
  • PHP防止站外表单跨站提交的几种办法详解
  • std::invoke()不支持重载函数
  • 【Linux】理解Linux中硬链接和软链接
  • 蓝桥杯真题2021c++省A题解
  • Vue3+vite2 博客前端开发
  • 【Verilog基础】二进制比较器
  • 一文讲清深力科工业与能源行业首选大电流 600V HVIC 高低边驱动产品SLM21814CJ-DG代替UCC27714DR 特性简述
  • 并发编程(十)-ScheduledThreadPoolExecutor源码分析