1. 程式人生 > >vue.js雙向資料繫結實現原理

vue.js雙向資料繫結實現原理

/*var dom = nodeToFragment(document.getElementById('app')); console.log(dom);*/ function compile(node,vm) { var reg =/\{\{(.*)\}\}/; //節點型別為元素 if(node.nodeType === 1){ var attr = node.attributes; //解析屬性 for(var i=0;i<attr.length;i++){ if
(attr[i].nodeName = 'v-model'){ var name = attr[i].nodeValue;//獲取v-model繫結的屬性名 //放在該位置原因是獲取name值 node.addEventListener('input',function (e) { //給相應的data屬性賦值,進而觸發該屬性的set方法 vm[name]=e.target.value; }); node.value = vm[name]; node.removeAttribute('v-model'
); } }; } //節點型別為text if(node.nodeType === 3){ if(reg.test(node.nodeValue)){ var name = RegExp.$1;//1.獲取匹配到的字串 name = name.trim(); //node.nodeValue = vm[name];//將data的值賦值給該node new Watcher(vm,node,name); } } } function
nodeToFragment(node,vm) {
var flag = document.createDocumentFragment(); var child; while(child = node.firstChild){ compile(child,vm); flag.append(child); } return flag; } function defineReactive(obj,key,val) { var dep = new Dep(); Object.defineProperty(obj,key,{ get:function () { if(Dep.target) dep.addSub(Dep.target); return val; }, set:function (newVal) { if(newVal===val) return ; val = newVal; //console.log(val); //作為釋出者發出通知 dep.notify(); } }); } function observe(obj,vm) { Object.keys(obj).forEach(function (key) { defineReactive(vm,key,obj[key]); }) } function Vue(options) { this.data = options.data; var data = this.data; observe(data,this); var id = options.el; var dom = nodeToFragment(document.getElementById(id),this); //編譯完成後,將dom返回到app中 document.getElementById('app').appendChild(dom); } function Dep() { this.subs = []; } Dep.prototype={ addSub:function (sub) { this.subs.push(sub); }, notify:function () { this.subs.forEach(function (sub) { sub.update(); }); } } function Watcher(vm,node,name) { Dep.target = this; this.name = name; this.node = node; this.vm = vm; this.update(); Dep.target=null; } Watcher.prototype={ update:function () { this.get(); this.node.nodeValue = this.value; }, //獲取data中的屬性值 get:function () { this.value = this.vm[this.name];//觸發相應屬性的get } }; var vm = new Vue({ el:'app', data:{ text:'hello world' } });