mvvm

class Vue {
    constructor(options) {
        /* 视图的驱动 */
        this.$el = options.el
        this._data = options.data
        this.$options = options
        this.$watchEvent = {}
        console.log(document.querySelector(this.$el),this._data,this.$options);
        const node = document.querySelector(this.$el)
        this.observe();
        this.proxyData();
        this.compile(node)
    }
    /* 渲染视图 */
    observe() {
        for (let key in this._data) {
            let value = this._data[key]
            let that = this;
            Object.defineProperty(this._data, key, {
                get() {
                    return value
                },
                set(val) {
                    value = val;
                    if (that.$watchEvent[key]) {
                        that.$watchEvent[key].forEach(item => {
                            item.update();
                        })
                    }
                }
            })
        }
    }
    /* 数据劫持的原理就是对data当中的每一个属性都使用Object.defineProperty绑定get/set方法 */
    proxyData() {
        for (let key in this._data) {
            Object.defineProperty(this, key, {
                get() {
                    return this._data[key]
                },
                set(val) {
                    return this._data[key] = val
                }
            })
        }
    }
    /* 模板解析: 
            将data数据渲染到模板当中
    */
    compile(node) {
        node.childNodes.forEach((item, index) => {
            if (item.nodeType === 1) {
                if (item.hasAttribute("@click")) {
                    let vmKey = item.getAttribute("@click").trim();
                    item.addEventListener("click", (e) => {
                        this.$options.methods[vmKey].bind(this)(e) 
                        console.log(this);
                    })
                }
                if (item.hasAttribute("v-model")) {
                    console.log(111+item.getAttribute("v-model"));
                    let vmKey = item.getAttribute("v-model").trim();
                    if (this.hasOwnProperty(vmKey)) {
                        // console.log(item,this[vmKey]);
                        item.value = this[vmKey]
                    }
                    item.addEventListener('input', (event) => {
                        this[vmKey] = item.value
                    })
                }
                if (item.childNodes.length > 0) {
                    this.compile(item)
                }
            }
            // console.log(item, item.nodeType);
            if (item.nodeType === 3) {
                // console.log(item, item.textContent);
                const reg = /\{\{(.*?)\}\}/g
                let text = item.textContent;
                console.log(text+222);
                item.textContent = text.replace(reg, (match, vmKey) => {
                    vmKey = vmKey.trim();
                    console.log(vmKey+111);
                    /* 渲染视图 */
                    // console.log(this, vmKey, item, 'textContent');
                    if (this.hasOwnProperty(vmKey)) {
                        let watch = new Watch(this, vmKey, item, 'textContent')
                        if (this.$watchEvent[vmKey]) {
                            this.$watchEvent[vmKey].push(watch)
                        } else {
                            this.$watchEvent[vmKey] = []
                            this.$watchEvent[vmKey].push(watch)
                        }
                    }
                    return this._data[vmKey]
                })
            }
        });
    }
}

class Watch {
    constructor(vm, key, node, attr) {
        this.vm = vm;
        this.node = node;
        this.key = key;
        this.attr = attr;
    }
    //执行改变
    update() {
        this.node[this.attr] = this.vm[this.key]
    }
}

 

<!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">
        {{msg}}
        <p>{{ msg }}</p>
        <h1>{{msg}}</h1>
        <h4>{{msg}}</h4>
        <h2>msg</h2>
        <button @click="btn">点我试试</button>
        <p @click="pppp">pppbiaoqian </p>
        <input type="text" v-model="msg">
    </div>
    <script src="./vue.js"></script>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                msg: "Hello World",
                message: "abcd"
            },
            methods: {
                btn(e) {
                    this.msg = "世上只有妈妈好!"
                    console.log(e, 333333);
                },
                pppp() {
                    console.log("abcddddd");
                }
            }
        })
        console.log(vm);
    </script>
</body>

</html>

  

posted @ 2024-04-06 10:09  肥瘦皆宜  阅读(12)  评论(0编辑  收藏  举报