砖搬多了就得想想怎么造砖,Vue使用多了,也得想想Vue是咋实现,Vue用着确实舒服,仔细了解一下,背后做的操作也太多了吧,但是再多的操作也是一个一个积累起来的吧!
先记录一下怎么实现data中值的渲染与修改
class Wvue extends EventTarget {
constructor(option) {
super()
console.log(option)
this.$options = option
this.compile()
this.observe(this.$options.data)
}
observe(data) {
let keys = Object.keys(data)
console.log(keys)
keys.forEach(key => {
this.defineData(data, key, data[key])
})
}
// 数据劫持函数
defineData(data, key, value) {
let that = this
Object.defineProperty(data, key, {
configurable: true,
enumerable: true,
get() { //获取data中数据时触发
// console.log('get数据了')
return value
},
set(newValue) { //给data中数据赋值时执行
console.log('哈哈哈,我设置数据了')
let event = new CustomEvent(key, { //向compileNode函数中传递要改变的值
detail: newValue
})
console.log(this)
// this.dispatchEvent(event)//注意这里的this指向vm.$options.data
that.dispatchEvent(event)
value = newValue
}
})
}
compile() {
let el = document.querySelector(this.$options.el)
this.compileNode(el)
}
compileNode(el) {
let childNodes = el.childNodes
childNodes.forEach(node => {
if (node.nodeType === 1) {
//标签
if (node.childNodes.length > 0) { //如果标签里还有嵌套标签或文本就继续调用
this.compileNode(node)
}
} else if (node.nodeType === 3) {
//文本节点
console.log(node)
let reg = /\{\{\s*(\S+)\s*\}\}/g
let textContent = node.textContent
console.log(textContent)
if (reg.test(textContent)) {
console.log('存在花括号')
let $1 = RegExp.$1
node.textContent = node.textContent.replace(reg, this.$options.data[$1])
this.addEventListener($1, e => {
console.log(e.detail)
//这里是第二次渲染,要把新值赋值给data中的旧值
let oldValue = this.$options.data[$1]
// console.log(oldValue) //打印出data中的旧值
let reg = new RegExp(oldValue)
node.textContent = node.textContent.replace(reg, e.detail)
//重新渲染视图
})
}
}
})
}
}
<div id="app">
{{message}}
<div class="content">
{{htmlData}}
</div>
</div>
<script src="./mvvm.js"></script>
<script>
let vm = new Wvue({
el: '#app',
data: {
message: '加油',
htmlData: 'hello'
}
})
setTimeout(() => {
vm.$options.data.message = '我要修改数据了'
})
</script>