vue 的 v-model 双向绑定 简单实现

html代码:

   

   

   

    Document

   

        {{ clickHere }}

       

{{ str }}

       

{{ clickHere }}

       

   

   

   

--------------------------------------------------------

js代码: 

class Vue {

    constructor(options) {

        this.options = options;

        this.$el = document.querySelector(options.el);

        this.$data = options.data;

        this.$methods = options.methods;

        this.$watchEvent = {};

        this.proxyData();

        this.compile(this.$el);

    }

    proxyData() {

        let that = this;

        for (let key in that.$data) {

            // 劫持 Vue(this) 的属性

            Object.defineProperty(

                that,

                key,

                {

                    get: function () {

                        console.log("获取 data." + key + "的值: ", that.$data[key])

                        return that.$data[key];

                    },

                    set: function (val) {

                        that.$data[key] = val;

                        if (that.$watchEvent[key]) {

                            that.$watchEvent[key].forEach((item, index) => {

                                item.update()

                            })

                        }

                    }

                }

            )

        }

    }

    compile(node) {

        let that = this;

        node.childNodes.forEach((item, index) => {

            // nodeType == 1 =>  node 节点, 带标签

            if (item.nodeType == 1) {

                // 递归节点-----------------------------------------------------------

                if (item.childNodes.length > 0) {

                    // 数据绑定

                    this.compile(item);

                }

                // @click 方法绑定-----------------------------------------------------------

                if (item.hasAttribute("@click")) {

                    // 获取方法名

                    let funName = item.getAttribute("@click").trim();

                    item.addEventListener('click', function (event) {

                        // 执行该方法名对应的方法 .call() 改变this指向为Vue 对象

                        that.$methods[funName].call(that, event);

                        console.log("compile : ", that);

                    })

                }

                // v-model 绑定-----------------------------------------------------------

                if (item.hasAttribute("v-model")) {

                    // 获取方法名

                    let funName = item.getAttribute("v-model").trim();

                    // 将数据绑定到视图

                    item.value = that[funName];

                    item.addEventListener('input', function (event) {

                        // 监听视图数据绑定到 model

                        that[funName] = item.value;

                    })

                }

                //-----------------------------------------------------------

            }

            // nodeType == 3  => 文本节点 不包含标签

            if (item.nodeType == 3) {

                let reg = /\{\{(.*?)\}\}/g;

                let text = item.textContent;

                item.textContent = text.replace(reg, function (match, vmKey) {

                    /*

                        function 参数 :  第一个是 匹配的全部字符

                                        第二个是 第一个元组

                                        第三个是 第二个元组

                                        ...

                    */

                    vmKey = vmKey.trim();

                    if (that[vmKey]) {

                        console.log(that[vmKey]);

                        let watcher = new Watch(that, vmKey, item, "textContent")

                        if (that.$watchEvent[vmKey]) {

                            that.$watchEvent[vmKey].push(watcher)

                        } else {

                            that.$watchEvent[vmKey] = [];

                            that.$watchEvent[vmKey].push(watcher)

                        }

                    }

                    return that.$data[vmKey];

                })

            }

        });

    }

}

// 用来动态更新视图

class Watch {

    constructor(vm, key, node, attr) {

        this.vm = vm;

        this.key = key;

        this.node = node;

        this.attr = attr;

    }

    update() {

        this.node[this.attr] = this.vm[this.key];

    }

}

你可能感兴趣的:(vue 的 v-model 双向绑定 简单实现)