实现简单MVVM数据响应

 

Html部分

<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>

JS部分

/*
 *  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);

猜你喜欢

转载自www.cnblogs.com/Ingots/p/12751864.html
今日推荐