1.声明一个发布订阅模式
let dep = {
map:{}, //map用于通过 事件名:【触发的函数1,触发的函数2】形式,来保存对象
collect(keyName,fn){
if(!this.map[keyName]){
this.map[keyName]=[]
}
this.map[keyName].push(fn)
}, //类似addEventListener,将监听的事件名都放入map中,在此案例中,一个属性名可能对应着多个m-v函数,同时触发
trigger(keyName){
this.map[keyName]&&this.map[keyName].forEach(fn=>fn())
} //通过trigger方法来触发对应事件名所带有的所有函数
}
2.声明对象
let data = {a:'张三',b:'李四',c:'王五'}
3.遍历对象,给对象中的每个属性添加get和set的响应事件
object.keys(data).forEach(key=>{
//将响应事件的函数抽离出来
defineReactive(data,key,data[key])
})
3.defineReactive函数中定义响应式内容
function defineReactive(data,key,value){
Object.defineProperty(data,key,()=>{
get(){
return value
},
set(newValue){
if(newValue === value) return
value = newValue
dep.trigger(key) //通过触发自定义事件,来使得修改某个属性的时候,触发该属性对应的多个相关视图的变化
}
})
}
4.定义一个compile函数,并触发(初始化),来丰富发布订阅里边的map
function compile(){
let nodes = document.querySelector('#ap').childNodes
nodes.forEach(node=>{
if(node.nodeType===1){
const attrs = node.attributes
Array.from(attrs).forEach(attr=>{
const dirName = attr.nodeName
const dataPro = attr.nodeValue
if(dirName ==='v-text'){
node.innerText = data[dataPro] //初始化渲染
dep.collect(dataPro,()=>{
node.innetText = data[dataPro]
})
}
if(dirName ==='v-model'){
node.value = data[dataPro] //初始化渲染
dep.collect(dataPro,()=>{
node.value = data[dataPro]
})
//设置监听事件
node.addEventListner('input',e=>{
data[dataPro]=.e.target.value
})
}
})
}
})
}
5. compile() 初始化渲染