实现ve双向绑定和nextTick(简单的)

97 阅读1分钟

新手上路还望各位大佬指教

简单实现下vue的双向绑定和nextTick

html片段

<body>
    <div id="title"></div>
</body>

js代码片段

        // 对象
        let obj = {
            name: 'will'
        }


        // Dep函数
        function Dep() {
            this.subs = []
        }
        Dep.prototype.addSub = function (sub) {
            this.subs.push(sub)
        }
        Dep.prototype.addSub = function (sub) {
            this.subs.push(sub);
        };
        Dep.prototype.depend = function () {
            if (Dep.target) {
                Dep.target.addDep(this);
            }
        };
        // 通知更新
        Dep.prototype.notify = function notify() {
            // stabilize the subscriber list first
            var subs = this.subs.slice();
            for (var i = 0, l = subs.length; i < l; i++) {
                subs[i].update();
            }
        };
        Dep.target = null;




        // 装载dep.target
        function pushTarget(target) {
            Dep.target = target;
        }
        // 卸载dep.target
        function popTarget(target) {
            Dep.target = target;
        }

        var uuid = 0
        // watcher函数
        function Watcher(expOrFn, opction) {
            this.id = ++uuid
            this.getter = expOrFn
            this.get()
            this.befor = opction.befor// 生命周期
        }
        Watcher.prototype.get = function () {
            //Dep.target = this
            pushTarget(this)
            this.getter()
            popTarget()
        }
        Watcher.prototype.addDep = function (dep) {
            //var id = dep.id;
            dep.addSub(this);
        };

        Watcher.prototype.update = function () {
            // 开启dom跟新队列
            queueWatcher(this)
        };
        Watcher.prototype.run = function () {
            this.befor() // 执行生命周期
            this.get()
        };

        var pedding = false; //等待开启队列
        // 异步任务
        var timerFunc = function () {
            Promise.resolve().then(flushCallbacks);
        };
        // 调用队列
        function flushCallbacks() {
            var copies = callbacks.slice(0);
            callbacks.length = 0;
            for (var i = 0; i < copies.length; i++) {
                copies[i]();
            }
        }


        // 执行队列
        var callbacks = [];
        // 将任务放入队列住的函数
        function nextTick(cb) {
            callbacks.push(function () {
                if (cb) {
                    cb.call()
                }
            })
            if (!pedding) { // 等待队列中的函数执行完再次加入队列
                pedding = true;
                timerFunc();
            }
        }
        // 执行更新dom
        var queue = []
        function flushSchedulerQueue() {
            for (index = 0; index < queue.length; index++) {
                queue[index].run()
            }
        }


        // 将watcher加入队列
        var has = {}
        function queueWatcher(watcher) {
            console.log(watcher)
            var id = watcher.id
            // 避免dom重复更新 只会加入一个watcher
            if (has[id] == null) {
                has[id] = true;
                queue.push(watcher)
                // 将更新dom事件加入 队列进行顺序调用
                nextTick(flushSchedulerQueue)
            }
        }

        // 双向绑定函数
        function Observer(data) {
            if (data.constructor == Object) {
                this.walk(data)
            }
        }
        Observer.prototype.walk = function (obj) {
            for (var key in obj) {
                defineReactive$$1(obj, key)
            }
        }

        // 双向绑定
        function defineReactive$$1(data, key) {
            var b = data[key];
            var dep = new Dep()
            Object.defineProperty(obj, 'name', {
                get: function (value) {
                    console.log('获取')
                    console.log(dep)
                    if (Dep.target) {
                        dep.depend()
                    }
                    return b
                },
                set: function (value) {
                    dep.notify()
                    b = value
                }
            })
        }
        
        
        // 模拟调用
        new Observer(obj)

        function updateComponent() {
            title.innerText = obj.name
        }
        new Watcher(updateComponent, {
            befor: function () {
                // 调用beforeUpdate生命周期
                console.log('beforeUpdate')
            }
        })
        // 绑定事件
        title.onclick = function () {
            //obj.name = 2
            for (let i= 0; i < 10; i++ ) {
                obj.name = i
            }
            nextTick(() => {
                console.log(title)
            })
            console.log(obj.name)
        }