vue的數據雙向綁定的小例子:javascript
。htmlhtml
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>vue數據雙向綁定原理</title> </head> <body> <h1 id="name"><<<<name>>>>>></h1> </body> <script src="testvuejs/observer.js"></script> <script src="testvuejs/watcher.js"></script> <script src="testvuejs/index.js"></script> <script type="text/javascript"> var ele = document.querySelector('#name'); var selfVue = new SelfVue({ name: 'hello world' }, ele, 'name'); window.setTimeout(function () { console.log('name值改變了'); selfVue.name = 'canfoo'; }, 2000); </script> </html>
index.jsvue
function SelfVue (data, el, exp) { var self = this; this.data = data; //把data裏的key直接綁定到this對象上 Object.keys(data).forEach(function(key) { self.proxyKeys(key); }); //對data的每一層級的屬性進行監聽,若是變化執行notify observe(data); // 初始化模板數據的值 el.innerHTML = this.data[exp]; new Watcher(this, exp, function (value) { el.innerHTML = value; }); return this; } SelfVue.prototype = { proxyKeys: function (key) { Object.defineProperty(this, key, { enumerable: false, configurable: true, get: ()=> { return this.data[key]; }, set: (newVal)=> { this.data[key] = newVal; } }); } }
observer.jsjava
function Observer(data) { this.data = data; this.walk(data); } Observer.prototype = { walk: function(data) { var self = this; Object.keys(data).forEach(function(key) { self.defineReactive(data, key, data[key]); }); }, defineReactive: function(data, key, val) { var dep = new Dep(); //對二級三級子屬性...進行監聽盡 observe(val); Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function() { if (Dep.target) { dep.addSub(Dep.target); } return val; }, set: function(newVal) { if (newVal === val) { return; } val = newVal; dep.notify(); } }); } }; function observe(value, vm) { if (!value || typeof value !== 'object') { return; } return new Observer(value); }; function Dep () { this.subs = []; } Dep.prototype = { addSub: function(sub) { this.subs.push(sub); }, notify: function() { this.subs.forEach(function(sub) { sub.update(); }); } }; Dep.target = null;
watcher.js緩存
function Watcher(vm, exp, cb) { this.cb = cb; this.vm = vm; this.exp = exp; //當new一個對象的時候,當即執行get方法,Dep的target爲Watcher本身 this.value = this.get(); // 將本身添加到訂閱器的操做 } Watcher.prototype = { update: function() { this.run(); }, run: function() { var value = this.vm.data[this.exp]; var oldVal = this.value; if (value !== oldVal) { this.value = value; this.cb.call(this.vm, value); } }, get: function() { Dep.target = this; // 緩存本身 var value = this.vm.data[this.exp] // this.vm.data[this.exp]:強制執行監聽器裏的get函數,使本身(Watcher {cb: ƒ, vm: SelfVue, exp: "name"})被添加上 Dep.target = null; // 釋放本身 return value; } };
原理:當new vue後,將data屬性直接給vm添加上,將屬性的每一級進行set get 當set新值時通知notify函數。執行 new watcher ,強制執行data的get 使watch被添加上。函數
當data set新值時,觸發notify函數,使全部watcher都執行update,watcher的update時,本地的value是舊值,取新值,回調函數更新view。this