目的: 是为了实现一个简易版本的 vue
使用Proxy
进行数据劫持,实现了渲染数据和双向绑定的功能
<div id="app">
<p>{{msg}}</p>
<p>{{num}}</p>
<input v-model="num" />
</div>
// Vue的实现过程
class Vue extends EventTarget {
constructor(option) {
super()
this.option = option
this._data = option.data
this.el = document.querySelector(option.el)
this.observe(this._data)
this.compileNode(this.el)
}
observe(data) {
let _self = this
this._data = new Proxy(data, {
set(target, prop, newValue) {
let event = new CustomEvent(prop, {
detail: newValue,
})
_self.dispatchEvent(event)
return Reflect.set(...arguments)
},
})
}
compileNode(el) {
let child = el.childNodes
;[...child].forEach((node) => {
if (node.nodeType === 3) {
let text = node.textContent
let reg = /\{\{\s*([^\s\{\}]+)\s*\}\}/g
if (reg.test(text)) {
let $1 = RegExp.$1
Object.keys(this._data).includes($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) {
let attr = node.attributes
if (attr.hasOwnProperty('v-model')) {
let key = attr['v-model'].nodeValue
node.value = this._data[key]
node.addEventListener('input', (e) => {
this._data[key] = node.value
console.log(this._data[key])
})
}
this.compileNode(node)
}
})
}
}
// 使用Vue
let app = new Vue({
el: '#app',
data: {
msg: 'Hello',
num: 2,
},
})