onLoad(option) { _self = this; _self.$data.xxxx = "te"; }
元素~~~~html
<input @click="categoryChange" :data-id="item.id" />
方法node
methods: { tabSelect(e) { this.TabCur = e.currentTarget.dataset.id; }, }
https://www.cnblogs.com/wangjiachen666/p/9883916.html緩存
Vue內部經過Object.defineProperty方法屬性攔截的方式,把data對象裏每一個數據的讀寫轉化成getter/setter,當數據變化時通知視圖更新。
也就是說:
輸入框內容變化時,data 中的數據同步變化。即 view => model 的變化。
data 中的數據變化時,文本節點的內容同步變化。即 model => view 的變化。函數
Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。this
完成了數據的'可觀測',即咱們知道了數據在何時被讀或寫了,那麼,咱們就能夠在數據被讀或寫的時候通知那些依賴該數據的視圖更新了,爲了方便,咱們須要先將全部依賴收集起來,一旦數據發生變化,就統一通知更新。其實,這就是典型的「發佈訂閱者」模式,數據變化爲「發佈者」,依賴對象爲「訂閱者」。雙向綁定
訂閱者Watcher 是一個 類,在它的構造函數中,定義了一些屬性:code
vm:一個Vue的實例對象;
exp:是node節點的v-model或v-on:click等指令的屬性值。如v-model="name",exp就是name;
cb:是Watcher綁定的更新函數;server
實現數據的雙向綁定,首先要對數據進行劫持監聽,因此咱們須要設置一個監聽器Observer,用來監聽全部屬性。若是屬性發上變化了,就須要告訴訂閱者Watcher看是否須要更新。由於訂閱者是有不少個,因此咱們須要有一個消息訂閱器Dep來專門收集這些訂閱者,而後在監聽器Observer和訂閱者Watcher之間進行統一管理的。htm
index.html對象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <h1 id="name"></h1> <input type="text"> <input type="button" value="改變data內容" onclick="changeInput()"> <script src="observer.js"></script> <script src="watcher.js"></script> <script> function myVue (data, el, exp) { this.data = data; observable(data); //將數據變的可觀測 el.innerHTML = this.data[exp]; // 初始化模板數據的值 new Watcher(this, exp, function (value) { el.innerHTML = value; }); return this; } var ele = document.querySelector('#name'); var input = document.querySelector('input'); var myVue = new myVue({ name: 'hello world' }, ele, 'name'); //改變輸入框內容 input.oninput = function (e) { myVue.data.name = e.target.value } //改變data內容 function changeInput(){ myVue.data.name = "難涼熱血" } </script> </body> </html>
observer.js
/** * 把一個對象的每一項都轉化成可觀測對象 * @param { Object } obj 對象 */ function observable (obj) { if (!obj || typeof obj !== 'object') { return; } let keys = Object.keys(obj); keys.forEach((key) =>{ defineReactive(obj,key,obj[key]) }) return obj; } /** * 使一個對象轉化成可觀測對象 * @param { Object } obj 對象 * @param { String } key 對象的key * @param { Any } val 對象的某個key的值 */ function defineReactive (obj,key,val) { let dep = new Dep(); Object.defineProperty(obj, key, { get(){ dep.depend(); console.log(`${key}屬性被讀取了`); return val; }, set(newVal){ val = newVal; console.log(`${key}屬性被修改了`); dep.notify() //數據變化通知全部訂閱者 } }) } class Dep { constructor(){ this.subs = [] } //增長訂閱者 addSub(sub){ this.subs.push(sub); } //判斷是否增長訂閱者 depend () { if (Dep.target) { this.addSub(Dep.target) } } //通知訂閱者更新 notify(){ this.subs.forEach((sub) =>{ sub.update() }) } } Dep.target = null;
watcher.js
class Watcher { constructor(vm,exp,cb){ this.vm = vm; this.exp = exp; this.cb = cb; this.value = this.get(); // 將本身添加到訂閱器的操做 } get(){ Dep.target = this; // 緩存本身 let value = this.vm.data[this.exp] // 強制執行監聽器裏的get函數 Dep.target = null; // 釋放本身 return value; } update(){ let value = this.vm.data[this.exp]; let oldVal = this.value; if (value !== oldVal) { this.value = value; this.cb.call(this.vm, value, oldVal); } } }