<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{ data }}
</div>
</body>
</html>
<script>
//手写vue实现原理 vue
// vue 数据劫持 + 发布订阅名单
class Vue{
//vue 生命周期 created时 将data中的数据挂载到了this上 this上的第一层的所有属性都有$包装
constructor(options){
options = options || {} ;
for(var attr in options){
this['&'+attr] = options[attr];
}
//当data存在并且有数据的时候 将属性通过数据劫持监听起来
for(var attr in options.data){
this[attr] = options.data[attr];
//将每个属性添加到订阅者名单中
observer.on({
attr:attr
});
Object.defineProperty(this,'_'+attr,{
get(){
console.log("我在获取值");
return this[attr];
},
set(newVal){
this[attr] = newVal;
console.log("我在设置值");
//当修改属性指的时候,
observer.emit.call(this,attr,newVal);
return this[attr];
}
})
}
//编译模板
this.mounted(options.el);
}
mounted(el){
//将差值语法替换为 对象中的数据
//选择元素
this.ele = this.chooseEl(el);
var reg = new RegExp('{{\\s?data\\s?}}','g');
this.ele.innerHTML = this.ele.innerHTML.replace(reg,this.msg);
//下一次的开始 是上一次的结束
this.lastTemplate = this.ele.innerHTML;
}
againChange(val){
var ele = this.ele;
var reg = new RegExp(''+ this.lastTemplate.trim(),'g');
ele.innerHTML = ele.innerHTML.replace(reg,val);
//下一次的开始 是上一次的结束
this.lastTemplate = ele.innerHTML;
}
chooseEl(el){
el = document.querySelectorAll(el);
if(el.length > 1){
return [].slice.call(el);
}else if(el.length === 1){
return el[0];
}else{
return null;
}
}
}
//创建发布订阅中名单
var observer = {
list:[],
on(p){
this.list.push(p);
},
emit(attr,newval){
observer.list.forEach(item => {
if( item.attr === attr ){
this.againChange(newval);
}
})
}
}
var vue = new Vue({
el:"#app",
data:{
msg:"欢迎来到前端编程世界"
}
})
</script>