深入浅出手撕简易VUE.JS和MVVM原理(终)

141 阅读1分钟

这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

一、实例化观察者时机

上次说到观察者实例化的时机,可以看到应该是在compiler类中订阅数据变化,所以在test、html等等方法中可以实例化观察者,以下是具体的实现。

getVal (expr, vm) { // 不断的通过.访问下去直到拿到真正的值
        return expr.split('.').reduce((data, currentVal) => {
            return data[currentVal];
        }, vm.$data)
    },
    getContentVal (expr, vm) {
        return expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
            return this.getVal(args[1], vm);
        })
    },
    text (node, expr, vm) {
        let value;
        if (expr.indexOf('{{') !== -1) { // 处理{{}}
            value = expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
                new watcher(vm, args[1], (newVal) => {
                    this.updater.textUpdater(node, this.getContentVal(expr, vm));
                })
                return this.getVal(args[1], vm);
            })
        } else {
            value = this.getVal(expr, vm); // 处理v-text
            new watcher(vm, expr, (newval) => {
                this.updater.textUpdater(node, newval);
            })
        }
        this.updater.textUpdater(node, value); // 在上面不同情况拿到值后直接更新视图即可
    },
    html (node, expr, vm) {
        const value = this.getVal(expr, vm);
        new watcher(vm, expr, (newval) => {
            this.updater.htmlUpdater(node, newval);
        })
        this.updater.htmlUpdater(node, value);
    },
    model (node, expr, vm) {
        const value = this.getVal(expr, vm);
        new watcher(vm, expr, (newval) => {
            this.updater.modelUpdater(node, newval);
        })
        this.updater.modelUpdater(node, value);
    }

二、实现双向的数据绑定和proxy代理

给input输入框添加一个input事件实现视图更改数据:

setVal (expr, vm, inputVal) { // 设置输入框输入的值
        return expr.split('.').reduce((data, currentVal) => {
            return data[currentVal] = inputVal; // 给老值赋值输入框的值
        }, vm.$data)
    },
    model (node, expr, vm) {
        const value = this.getVal(expr, vm);
        new watcher(vm, expr, (newval) => { // 数据更改视图
            this.updater.modelUpdater(node, newval);
        })
        node.addEventListener('input', (e) => { //视图更改数据
            this.setVal(expr, vm, e.target.value);
        })
        this.updater.modelUpdater(node, value);
    }

至于代理的话是想要直接就this.属性不需要this.$data.属性,这就可以在大类里面声明一个代理的方法,具体只需要遍历所有的data去劫持返回在数据中的data:

proxyData(data) {
        for(const key in data) {
            Object.defineProperty(this, key, {
                get() {
                    return data[key];
                },
                set(newVal) {
                    data[key] = newval;
                }
            })
        }
    }

至此就已经实现了MVVM原理,亲手构建起一个简易的Vue框架,各位也可以试试看自己搭建的框架与Vue有什么差别,各位加油!