1、myvue.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 观察者模式-EventTarget 实现数据响应式</title>
<script src="./myvue.js"></script>
</head>
<body>
<div id="app">
<div>
{{message}}
</div>
fafafa{{message}}fafafa
</div>
<script>
// 一:初次渲染你
// 二: 响应式: 1、数据被修改(数据观察,数据劫持); 2、视图更新(观察者模式)
let vm = new MyVue({
el:'#app',
data:{
message:'数据'
}
});
console.log(vm);
setTimeout(() => {
vm._data.message = "修改的值";
},1000);
</script>
</body>
</html>
2、myvue.js
class MyVue extends EventTarget{
constructor(options){
super();
this.$options = options;
this._data = options.data;
this.observe(this._data);
this.compile();
}
// observe-defineProperty
observe(data){
const _this = this;
let keys = Object.keys(data);
keys.forEach(key => {
let value = data[key];
Object.defineProperty(data, key, {
configurable: true,
enumerable: true,
get(){
console.log('get');
return value;
},
set(newValue){
console.log('set');
// 触发事件
_this.dispatchEvent(new CustomEvent(key, {
detail: newValue
}));
value = newValue;
}
})
});
}
compile(){
let ele = document.querySelector(this.$options.el);
this.compileNodes(ele);
}
compileNodes(ele){
let childNodes = ele.childNodes;
childNodes.forEach(node => {
if(node.nodeType === 1){
// 元素节点0
if(node.childNodes.length > 0){
this.compileNodes(node);
}
}else{
// 文本节点
let reg = /\{\{\s*([^{}\s]+)\s*\}\}/g;
let textContent = node.textContent;
if(reg.test(textContent)){
let $1 = RegExp.$1;
node.textContent = node.textContent.replace(reg, this._data[$1]);
//事件监听
this.addEventListener($1, (e) => {
console.log('视图更新',e);
let oldValue = this._data[$1];
let newValue = e.detail;
node.textContent = node.textContent.replace(oldValue, newValue);
});
}
}
})
}
}