页面代码:
<!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) } }) }}