您好,登錄后才能下訂單哦!
這篇“Vue2響應式系統之嵌套怎么實現”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Vue2響應式系統之嵌套怎么實現”文章吧。
在 開發中肯定存在組件嵌套組件的情況,類似于下邊的樣子。Vue
<!-- parent-component --> <div> <my-component :text="inner"></my-component> {{ text }} <div> <!-- my-component--> <div>{{ text }}</div>
回到我們之前的響應式系統,模擬一下上邊的情況:
import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { text: "hello, world", inner: "內部", }; observe(data); const updateMyComponent = () => { console.log("子組件收到:", data.inner); }; const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父組件收到:", data.text); }; new Watcher(updateParentComponent); data.text = "hello, liang";
可以先 分鐘考慮一下上邊輸出什么?1
首先回憶一下 會做什么操作。new Watcher
第一步是保存當前函數,然后執行當前函數前將全局的 賦值為當前 對象。Dep.target
Watcher
接下來執行 函數的時候,如果讀取了相應的屬性就會觸發 ,從而將當前 收集到該屬性的 中。getter
get
Watcher
Dep
import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { text: "hello, world", inner: "內部", }; observe(data); const updateMyComponent = () => { console.log("子組件收到:", data.inner); }; const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父組件收到:", data.text); }; new Watcher(updateParentComponent); data.text = "hello, liang";
我們再一步一步理清一下:
new Watcher(updateParentComponent);
將 賦值為保存了 函數的 。Dep.target
updateParentComponent
Watcher
接下來執行 函數。updateParentComponent
new Watcher(updateMyComponent);
將 賦值為保存了 函數的 。Dep.target
updateMyComponent
Watcher
接下來執行 函數。updateMyComponent
const updateMyComponent = () => { console.log("子組件收到:", data.inner); }; // 讀取了 inner 變量。 // data.inner 的 Dep 收集當前 Watcher(保存了 `updateMyComponent` 函數)
const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父組件收到:", data.text); }; // 讀取了 text 變量。 // data.text 的 Dep 收集當前 Watcher (保存了 `updateMyComponent` 函數)
data.text = "hello, liang";
觸發 的 函數,執行它依賴的 ,而此時是 函數。text
set
Watcher
updateMyComponent
所以上邊代碼最終輸出的結果是:
子組件收到: 內部 // new Watcher(updateMyComponent); 時候輸出
父組件收到: hello, world // new Watcher(updateParentComponent); 時候輸出
子組件收到: 內部 // data.text = "hello, liang"; 輸出
然而子組件并不依賴 ,依賴 的父組件反而沒有執行。data.text
data.text
上邊的問題出在我們保存當前正在執行 時候使用的是單個變量 。Watcher
Dep.target = null; // 靜態變量,全局唯一
回憶一下學習 語言或者匯編語言的時候對函數參數的處理:C
function b(p) { console.log(p); } function a(p) { b("child"); console.log(p); } a("parent");
當函數發生嵌套調用的時候,執行 函數的時候我們會先將參數壓入棧中,然后執行 函數,同樣將參數壓入棧中, 函數執行完畢就將參數出棧。此時回到 函數就能正確取到 參數的值了。a
b
b
a
p
對應于 的收集,我們同樣可以使用一個棧來保存,執行函數前將 壓入棧,執行函數完畢后將 彈出棧即可。其中, 始終指向棧頂 ,代表當前正在執行的函數。Watcher
Watcher
Watcher
Dep.target
Watcher
回到 代碼中,我們提供一個壓棧和出棧的方法。Dep
import { remove } from "./util"; let uid = 0; export default class Dep { ... 省略 } Dep.target = null; // 靜態變量,全局唯一 // The current target watcher being evaluated. // This is globally unique because only one watcher // can be evaluated at a time. const targetStack = []; export function pushTarget(target) { targetStack.push(target); Dep.target = target; } export function popTarget() { targetStack.pop(); Dep.target = targetStack[targetStack.length - 1]; // 賦值為棧頂元素 }
然后 中,執行函數之前進行入棧,執行后進行出棧。Watcher
import { pushTarget, popTarget } from "./dep"; export default class Watcher { constructor(Fn) { this.getter = Fn; this.depIds = new Set(); // 擁有 has 函數可以判斷是否存在某個 id this.deps = []; this.newDeps = []; // 記錄新一次的依賴 this.newDepIds = new Set(); this.get(); } /** * Evaluate the getter, and re-collect dependencies. */ get() { /************修改的地方*******************************/ pushTarget(this); // 保存包裝了當前正在執行的函數的 Watcher /*******************************************/ let value; try { value = this.getter.call(); } catch (e) { throw e; } finally { /************修改的地方*******************************/ popTarget(); /*******************************************/ this.cleanupDeps(); } return value; } ... }
回到開頭的場景,再來執行一下:
import { observe } from "./reactive"; import Watcher from "./watcher"; const data = { text: "hello, world", inner: "內部", }; observe(data); const updateMyComponent = () => { console.log("子組件收到:", data.inner); }; const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父組件收到:", data.text); }; new Watcher(updateParentComponent); data.text = "hello, liang";
執行 的時候將 入棧。new Watcher(updateParentComponent);
Watcher
進入 函數,執行 的時候將 入棧。updateParentComponent
new Watcher(updateMyComponent);
Watcher
執行 函數, 收集當前 ,執行完畢后 出棧。updateMyComponent
data.inner
Dep.target
Watcher
繼續執行 函數, 收集當前 。updateParentComponent
data.text
Dep.target
此時依賴就變得正常了, 會觸發 函數,從而輸出如下:data.text
updateParentComponent
子組件收到: 內部
父組件收到: hello, world
子組件收到: 內部
父組件收到: hello, liang
以上就是關于“Vue2響應式系統之嵌套怎么實現”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。