您好,登錄后才能下訂單哦!
這篇文章主要介紹“Vue中數據響應式的原理分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Vue中數據響應式的原理分析”文章能幫助大家解決問題。
改造數據
我們先來嘗試寫一個函數,用于改造對象:
為什么要先寫這個函數呢? 因為改造數據是一個最基礎也是最重要的步驟,之后所有的步驟都會依賴這一步。
// 代碼 1.1 function defineReactive (obj,key,val) { Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function () { return val; }, set: function (newVal) { //判斷新值與舊值是否相等 //判斷的后半段是為了驗證新值與舊值都為NaN的情況 NaN不等于自身 if(newVal === val || (newVal !== newVal && value !== value)){ return ; } val = newVal; } }); }
例如const obj = {},然后再調用defineReactive(obj,'a',2)方法,此時在函數內,val=2,然后每次獲取obj.a的值的時候都是獲取val的值,設置obj.a的時候也是設置val的值。(每次調用defineReactive都會產生一個閉包保存了val的值);
流程討論
經過驗證之后,發現這個函數確實可以使用的。然后我們來討論一下響應的流程:
輸入數據
改造數據(defineReactive())
如果數據變動 => 觸發事件
我們來看第三步,數據變動如何觸發之后的事件呢?仔細思考一下,如果要改變數據,那么必須先set數據,那么我們直接set()里面添加方法就ok了呀。
然后還有一個重要問題:
依賴收集
我們怎么知道數據改變之后要觸發的是什么事件呢?在Vue中:
使用數據 => 視圖; 使用了數據來渲染視圖,那么在獲取數據的時候收集依賴是最佳的時機,Vue在改造數據屬性的時候生成一個Dep實例,用于收集依賴。
// 代碼 1.2 class Dep { constructor(){ //訂閱的信息 this.subs = []; } addSub(sub){ this.subs.push(sub); } removeSub (sub) { remove(this.subs, sub); } //此方法的作用等同于 this.subs.push(Watcher); depend(){ if (Dep.target) { Dep.target.addDep(this); } } //這個方法就是發布通知了 告訴你 有改變啦 notify(){ const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update(); } } } Dep.target = null;
代碼1.2就是Dep的部分代碼,暫時只需要知道2個方法的作用就可以了
depend() --- 可以理解為收集依賴的事件,不考慮其他方面的話 功能等同于addSub()
notify() --- 這個方法更為直觀了,執行所有依賴的update()方法。就是之后的改變視圖啊 等等。
本篇主要討論數據響應的過程,不深入討論 Watcher類,所以Dep中的方法知道作用就可以了。
然后就是改變代碼1.1了
//代碼 1.3 function defineReactive (obj,key,val) { const dep = new Dep(); Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function () { if(Dep.target){ //收集依賴 等同于 dep.addSub(Dep.target) dep.depend() } return val; }, set: function (newVal) { if(newVal === val || (newVal !== newVal && val !== val)){ return ; } val = newVal; //發布改變 dep.notify(); } }); }
這代碼中有一個疑點,Dep.target是什么?為什么要有Dep.target才會收集依賴呢?
Dep是一個類,Dep.target是類的屬性,并不是dep實例的屬性。
Dep類在全局可用,所以Dep.target在全局能訪問到,可以任意改變它的值。
get這個方法使用很平常,不可能每次使用獲取數據值的時候都去調用dep.depend()。
dep.depend()實際上就是dep.addSub(Dep.target)。
那么最好方法就是,在使用之前把Dep.target設置成某個對象,在訂閱完成之后設置Dep.target = null。
驗證
是時候來驗證一波代碼的可用性了
//代碼 1.4 const obj = {};//這一句是不是感覺很熟悉 就相當于初始化vue的data ---- data:{obj:{}}; //低配的不能再低配的watcher對象(源碼中是一個類,我這用一個對象代替了) const watcher = { addDep:function (dep) { dep.addSub(this); }, update:function(){ html(); } } //假裝這個是渲染頁面的 function html () { document.querySelector('body').innerHTML = obj.html; } defineReactive(obj,'html','how are you');//定義響應式的數據 Dep.target = watcher; html();//第一次渲染界面 Dep.target = null;
此時瀏覽器上的界面是這樣的
然后在下打開了控制臺開始調試,輸入:
obj.html = 'I am fine thank you'
然后就發現,按下回車的那一瞬間,奇跡發生了,頁面變成了
關于“Vue中數據響應式的原理分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。