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

html代码:

<!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="app">

        {{ clickHere }}

        <h1>{{ str }}</h1>

        <h2 @click="func1">{{ clickHere }}</h2>

        <input v-model="str" type="text">

    </div>

    <script src="../js/myVue.js"></script>

    <script>

        let myVue = new Vue({

            el: "#app",

            data: {

                str: "你好234",

                clickHere: "点击这里",

            },

            methods: {

                func1(e) {

                    this.clickHere = "点击这里aaa"

                    console.log(this.clickHere);

                    console.log(this);

                    console.log(e);

                }

            }

        })

    </script>

</body>

</html>

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

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];

    }

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容