<div id="app">
<div>
<p>姓名:{{ name }},年龄: {{age}}</p>
<p v-html="htmlData"></p>
<input type="text" v-model="modelData" />
<p>{{modelData}}</p>
</div>
{{message}} {{modelData}} {{message}}
</div>
/*
* v-model 双向绑定:视图修改了会自动同步数据,数据了会自动同步视图
*/
/*
* 1.编译根据当前元素结构将数据编译进去, 实现{{}}匹配,实现v-html和v-mode两个指令
* 2.添加数据劫持,完成数据响应式
*/
class kVue extends EventTarget {
constructor(option){
super();
this.$option = option;
let el = document.querySelector(this.$option.el);
this.compileNode(el);
this.observe(this.$option.data);
}
// 给数据添加劫持
observe(data){
let keys = Object.keys(data);
keys.forEach(key=>{
this.dataProxy(data,key,data[key]);
});
}
// 完成数据劫持,在数据发生变化的时候去触发视图的变化
dataProxy(data,key,value){
let _this = this;
Object.defineProperty(data,key,{
configurable: true,
enumerable: true,
get(){
return value;
},
set(newVal){
// console.log(this); // defineProperty中的this是指向data的
value = newVal; //将老值替换成新的值,此时视图未更新,得重新编译一次
let event = new Event(key);
event.value = newVal;
console.log(event);
_this.dispatchEvent(event); //* 触发事件
}
});
}
// 编译
compileNode(el){
let child = el.childNodes;
child.forEach(node => {
// nodeType: 1元素、2属性 3文本
if(node.nodeType === 1){
let attrs = node.attributes;
console.log(attrs);
[...attrs].forEach(attr=>{
let attrName = attr.name; // 属性名字
if(attrName.indexOf("v-") === 0){
attrName = attrName.substr(2);
let attrVal = attr.value;
if(attrName == "html"){
node.innerHTML = this.$option.data[attrVal];
//* 监听事件, 同步视图
this.addEventListener(attrVal,({value})=>{
node.innerHTML = this.$option.data[attrVal];
});
} else if(attrName == "model"){
node.value = this.$option.data[attrVal];
// 监听视图改变,同步修改数据,此时还未修改到视图
node.addEventListener("input",({target})=>{
// console.log(arg);
this.$option.data[attrVal] = target.value;
});
//* 监听事件, 同步视图
this.addEventListener(attrVal,()=>{
node.value = this.$option.data[attrVal];
});
}
}
});
// 若还有子节点,则继续编译
if(node.childNodes.length > 0){
this.compileNode(node);
}
} else if(node.nodeType == 3){
console.dir(node.textContent,3);
let reg = /\{\{\s*(\S+)\s*\}\}/g;
let startTextContent = node.textContent;
if(reg.test(node.textContent)){
node.textContent = startTextContent.replace(reg,(...arg)=>{
console.log(arg);
this.addEventListener(arg[1],()=>{ //* 监听事件, 同步视图
node.textContent = startTextContent.replace(reg,(...arg)=>{
return this.$option.data[arg[1]];
});
});
return this.$option.data[arg[1]];
})
}
}
});
}
}
let kvue = new kVue({
el: "#app",
data: {
message: "Hello Word",
modelData: "呵呵",
name: "凯旋",
age: 8,
htmlData: "<strong>学习学习学习</strong>"
}
});
setTimeout(()=>{
kvue.$option.data.modelData = "新的值";
},1000);