<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <div> <div v-text="myText"></div> </div> <input type="text" v-model="myText"> </div> <script src="likeVue.js"></script> <script> let vm=new Vue({ el:'#app', data:{ myText:'这是数据驱动' } }) </script> </body> </html>
class Vue { constructor(setting){ this.$el=document.querySelector(setting.el); this.$data=setting.data; //创建容器保存订阅者信息 this._directive={},this.newObj={}; this.Observer(this.$data); this.Complie(this.$el); } //解析指令 Complie(el){ let nodes =el.children; for(let i=0;i<nodes.length;i++){ let node =nodes[i] if(node.hasAttribute('v-text')){ let attrval=node.getAttribute('v-text'); //push ??订阅者 this._directive[attrval].push(new Watcher(node,this,attrval,'innerHTML')); } if(node.hasAttribute('v-model')){ let attrval=node.getAttribute('v-model'); //push ??订阅者 this._directive[attrval].push(new Watcher(node,this,attrval,'value')); //dom变化更新数据 node.addEventListener('input',()=>{ this.$data[attrval]=node.value; this.newObj[attrval]=node.value; // this._directive[attrval].forEach(item=>{ // item.update() // }); }) } if(node.children.length){ this.Complie(node) } } } //劫持数据 Observer(data){ for (let key in data) { this._directive[key]=[]; // let val =data[key]; // let watcher =this._directive[key]; // Object.defineProperty(this.$data,key,{ // get:function(){ // return val; // }, // set:function(newVal){ // if(newVal!==val){ // val =newVal; // watcher.forEach(item=>{ // item.update() // }) // // } // } // }) } let self=this; this.newObj = new Proxy(data, { get: function(target, key, receiver) { console.log(`getting ${key}!`); return Reflect.get(target, key, receiver); }, set: function(target, key, value, receiver) { console.log(target, key, value, receiver); self._directive[key].forEach(item=>{ item.update(); }) return Reflect.set(target, key, value, receiver); }, }); } } //订阅者-->负责自己更新本身状态 class Watcher{ constructor(el,vm,exp,attr){ this.el=el; this.vm=vm; this.exp=exp; this.attr=attr; this.update(); } update(){ this.el[this.attr]=this.vm.$data[this.exp] } }