乐趣区

关于前端:双向绑定demo

页面代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script src="./myvue.js"></script>
</head>
<body>
    <div id="app">
        {{name}}
        <div>{{message}}</div>
        <input v-model="test" type="text">
        {{test}}
    </div>
    <script type="text/javascript">
      let vm =  new vue({
            el: '#app',
            data: {
                name: 'lili',
                message: 'test',
                test: '双向绑定'
            }
        })
        // console.log(vm);
        // console.log(vm._data.name);
    </script>
</body>
</html>

myvue.js 代码:

class vue extends EventTarget{ // 定义自定义事件,须要继承 EventTarget
    constructor(option) {super() // 继承要执行父类的构造函数
        this.option = option
        this._data = this.option.data
        this.el = document.querySelector(this.option.el)
        this.observe(this._data)
        this.compileNode(this.el)
    }

    observe(data) {
        let self = this
        this._data = new Proxy(data, {set(target, prop, newValue) {console.log(newValue);

                let event = new CustomEvent(prop, { // 发送自定义事件, 实现双绑
                    detail: newValue
                })
                self.dispatchEvent(event)

                return Reflect.set(...arguments)
            }
        })
    }

    compileNode(el) {
        let child = el.childNodes // 伪数组
        console.log(child);
        [...child].forEach(node => { // 伪数开展为数组
            if(node.nodeType === 3) { // 文本节点
                console.log('这是一个文本节点');
                let text = node.textContent
                let reg = /\{\{\s*([^\s\{\}]+)\s*\}\}/g
                if (reg.test(text)) {
                    let $1 = RegExp.$1 // 与正则表达式匹配的第一个 子匹配
                    this._data[$1] && (node.textContent = text.replace(reg, this._data[$1]))
                    
                    this.addEventListener($1, e=> { // 接管自定义事件, 实现双绑
                        node.textContent = text.replace(reg, e.detail)
                    })
                }
            } else if (node.nodeType === 1) {console.log('这是一个元素节点');
                let attr = node.attributes
                if(attr.hasOwnProperty('v-model')) {let keyName = attr['v-model'].nodeValue
                    node.value = this._data[keyName]
                    node.addEventListener('input', e => {this._data[keyName] = node.value
                    })
                }
                this.compileNode(node)
            }
        })
    }
}
退出移动版