Vue简单实现

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

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

<body>
    <div id="app">
        <input type="text" v-model="msg">
        <h1>{{msg}}</h1>
        <h1 v-html="msg"></h1>
        <button @click="setMsg">设置</button>
    </div>

    <script type="text/javascript">
        class Vue {
            constructor(opations) {
                this.$el = document.querySelector(opations.el);
                this.$opations = opations;
                this.$watchEvent = {};
                this.peoxyData(); //代理opations的data数据
                this.obsevice(); //监听
                this.compile(this.$el); //编译
            }
            peoxyData() {
                for (let key in this.$opations.data) {
                    Object.defineProperty(this, key, {
                        configurable: false,
                        enumerable: true,
                        get() {
                            return this.$opations.data[key]
                        },
                        set(val) {
                            this.$opations.data[key] = val;
                        }
                    })
                }
            }
            obsevice() {
                for (let key in this.$opations.data) {
                    let value = this.$opations.data[key];
                    let self = this;
                    Object.defineProperty(this.$opations.data, key, {
                        configurable: false,
                        enumerable: true,
                        get() {
                            return value
                        },
                        set(val) {
                            value = val;
                            if (self.$watchEvent[key]) {
                                self.$watchEvent[key].forEach((item, index) => {
                                    item.updata()
                                });
                            }
                        }
                    })
                }
            }
            compile($el) {
                $el.childNodes.forEach((node, index) => {
                    if (node.nodeType == 1) {
                        if (node.hasAttribute("v-html")) {
                            let vmKey = node.getAttribute("v-html").trim();
                            node.innerHTML = this[vmKey];
                            let watcher = new Watch(this, vmKey, node, "innerHTML");
                            this.$watchEvent[vmKey] = [...(this.$watchEvent[vmKey] || []), watcher];
                            node.removeAttribute("v-html");
                        }
                        if (node.hasAttribute("v-model")) {
                            let vmKey = node.getAttribute("v-model").trim();
                            if (this.hasOwnProperty(vmKey)) {
                                node.value = this[vmKey];
                                let watcher = new Watch(this, vmKey, node, "value");
                                this.$watchEvent[vmKey] = [...(this.$watchEvent[vmKey] || []), watcher];
                                node.addEventListener("input", e => {
                                    this[vmKey] = node.value
                                })
                                node.removeAttribute("v-model");
                            }
                        }
                        if (node.hasAttribute("@click")) {
                            let vmKey = node.getAttribute("@click").trim();
                            node.addEventListener("click", e => {
                                this.$opations.methods[vmKey].call(this, e)
                            })
                            node.removeAttribute("@click");
                        }
                    }
                    if (node.nodeType == 3) {
                        let reg = /\{\{(.*?)\}\}/;
                        let text = node.textContent;
                        node.textContent = node.textContent.replace(reg, (val, vmKey) => {
                            vmKey = vmKey.trim();
                            if (this.hasOwnProperty(vmKey)) {
                                node.value = this[vmKey];
                                let watcher = new Watch(this, vmKey, node, "textContent");
                                this.$watchEvent[vmKey] = [...(this.$watchEvent[vmKey] || []), watcher];
                            }
                            return this[vmKey]
                        })
                    }
                    if (node.childNodes.length > 0) {
                        this.compile(node)
                    }
                })

            }
        };
        class Watch {
            constructor(vm, key, node, attr, aType) {
                this.vm = vm; //Vue实力对象
                this.key = key; //绑定的属性
                this.node = node; //html节点
                this.attr = attr; //绑定的属性名称
            }
            updata() {
                this.node[this.attr] = this.vm[this.key];
            }
        }
        let app = new Vue({
            el: "#app",
            data: {
                msg: "ASD"
            },
            methods: {
                setMsg() {
                    this.msg = "QWE"
                }
            }
        })
    </script>
</body>

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