您现在的位置是:Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款 > 

03 js觀察者模式和發布訂閱(vuejs源碼用了什么設計模式,具體點的)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款2024-06-01 11:01:14【】5人已围观

简介行內容替換,替換為vm實例中的data中的內容然后,在向碎片化文檔中添加節點時,每個節點都處理一下。創建Vue的實例化函數效果圖如下:我們成功將內容都綁定到了輸入框與文本節點上!4、實現任務2——【v

行內容替換,替換為vm實例中的data中的內容

然后,在向碎片化文檔中添加節點時,每個節點都處理一下。

創建Vue的實例化函數

效果圖如下:

我們成功將內容都綁定到了輸入框與文本節點上!

4、實現任務2——【view => model

對于此任務,我們從輸入框考慮,輸入框的問題,輸入框如何改變data。我們通過事件監聽器keyup,input等,來獲取到最新的value,然后通過Object.defineProperty將獲取的最新的value,賦值給實例vm的text,我們把vm實例中的data下的text通過Object.defineProperty設置為訪問器屬性,這樣給vm.text賦值,就觸發了set。set函數的作用一個是更新data中的text,另一個等到任務三再說。

首先實現一個響應式監聽屬性的函數。一旦有賦新值就發生變化

然后,實現一個觀察者,對于一個實例 每一個屬性值都進行觀察。

改寫編譯函數,注意由于改成了訪問器屬性,訪問的方法也產生變化,同時添加了事件監聽器,把實例的text值隨時更新

實例函數中,觀察data中的所有屬性值,注意增添了observe

最終我們改變input中的內容能改變data中的數據,單頁面卻沒有刷新

4、實現任務3——【model => view】

通過修改vm實例的屬性 該改變輸入框的內容 與 文本節點的內容。

這里涉及到一個問題 需要我們注意,當我們修改輸入框,改變了vm實例的屬性,這是1對1的。

但是,我們可能在頁面中多處用到 data中的屬性,這是1對多的。也就是說,改變1個model的值可以改變多個view中的值。

這就需要我們引入一個新的知識點:

訂閱/發布者模式

訂閱發布模式(又稱觀察者模式)定義了一種一對多的關系,讓多個觀察者同時監聽某一個主題對象,這個主題對象的狀態發生改變時就會通知所有觀察者對象。

發布者發出通知 => 主題對象收到通知并推送給訂閱者 => 訂閱者執行相應操作

1

舉個例子:

之前提到的set函數的第二個作用 就是來提醒訂閱者 進行noticy操作,告訴他們:“我的text變了!” 文本節點變成了訂閱者,接到消息后,立馬進行update操作

回顧一下,每當 new 一個 Vue,主要做了兩件事:第一個是監聽數據:observe(data),第二個是編譯 HTML:nodeToFragement(id)。

在監聽數據的過程中,我們會為 data 中的每一個屬性生成一個主題對象 dep。

在編譯 HTML 的過程中,會為每個與數據綁定相關的節點生成一個訂閱者 watcher,watcher 會將自己添加到相應屬性的 dep 容器中。

我們已經實現:修改輸入框內容 => 在事件回調函數中修改屬性值 => 觸發屬性的 set 方法。

接下來我們要實現的是:發出通知 dep.notify() => 觸發訂閱者的 update 方法 => 更新視圖。

這里的關鍵邏輯是:如何將 watcher 添加到關聯屬性的 dep 中。

注意: 我把直接賦值的操作改為了 添加一個 Watcher 訂閱者

那么,Watcher又該做些什么呢?

首先,將自己賦給了一個全局變量 Dep.target;

其次,執行了 update 方法,進而執行了 get 方法,get 的方法讀取了 vm 的訪問器屬性,從而觸發了訪問器屬性的 get 方法,get 方法中將該 watcher 添加到了對應訪問器屬性的 dep 中;

再次,獲取屬性的值,然后更新視圖。

最后,將 Dep.target 設為空。因為它是全局變量,也是 watcher 與 dep 關聯的唯一橋梁,任何時刻都必須保證 Dep.target 只有一個值。

最終我們就實現了這個雙向數據綁定功能,雖然很繁瑣,但我相信,你多打幾遍,一定會對你有所幫助,加油吧!!

vue數據雙向綁定原理

vue.js 采用數據劫持結合發布者-訂閱者模式的方式,通過 Object.defineProperty() 來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。

首先我們為每個vue屬性用Object.defineProperty()實現數據劫持,在監聽數據的過程中,為每個屬性分配一個訂閱者集合的管理數組dep;然后在編譯的時候在該屬性的數組dep中添加訂閱者 watcher,v-model會添加一個訂閱者,{ { }}也會,v-bind也會,只要用到該屬性的指令理論上都會,接著為input會添加監聽事件,修改值就會為該屬性賦值,觸發該屬性的set方法,在set方法內通知訂閱者數組dep,訂閱者數組循環調用各訂閱者的update方法更新視圖。

實現步驟:修改輸入框內容 => 在事件回調函數中修改屬性值 => 觸發屬性的 set 方法=>發出通知 dep.notify() => 觸發訂閱者的 update 方法 => 更新視圖。

流程圖 :

在實例化一個Vue對象的時候,會傳進去一個data對象,之后分成兩個進程,一個進程是對掛載目標元素模板里的v-model和{ { }};兩個指令進行編譯。另一個進程是對傳進去的data對象里面的數據進行監聽。

上圖中,observe是利用Object.defineProperty()對傳入的data對象進行數據監聽,在數據改變的時候觸發該屬性的set方法,更新該屬性的值,并發布消息,我(該屬性)的值變了。

買粉絲pile是編譯器,找到vue的指令v-model所在的元素,將data中該屬性的值賦給元素的value,并給這個元素添加二級監聽器,在元素的值改變的時候,將新值賦給data里面同名屬性,這個時候就完成了單向數據綁定,視圖 >> 模型。

那么最終的由模型到視圖的更新,依賴于dep和watcher,dep會收集訂閱者,就是綁定了data里面屬性的元素,在數據更新的時候,會觸發該屬性的set方法,在set里觸發該屬性的消息發布通知函數。而Watcher根據收到的數據變化通知,更新相應的數據。

dep這個東東給大家解釋一下,就是data里的每個屬性都有一個dep對象,dep對象里可以有很多訂閱者(watcher),但是只有一個添加訂閱者的方法和一個發布變化通知的方法,就是模板上可以有多處元素綁定data里的同一個屬性值,所以dep是依賴于data里面的屬性的。

而Watcher是每個{ { }}有一個,初次編譯的時候,會在new的時候自動更新一下模板的數據,等到下次數據改變的時候,由dep通知數據更新,直接調用watcher的update方法,更新模板的綁定數據。

observer 模塊共分為這幾個部分:

示意圖如下:

Observer的構造函數

value是需要被觀察的數據對象,在構造函數中,會給value增加 ob 屬性,作為數據已經被Observer觀察的標志。如果value是數組,就使用observeArray遍歷value,對value中每一個元素調用observe分別進行觀察。如果value是對象,則使用walk遍歷value上每個key,對每個key調用defineReactive來獲得該key的set/get控制權。

Dep是Observer與Watcher之間的紐帶,也可以認為Dep是服務于Observer的訂閱系統。Watcher訂閱某個Observer的Dep,當Observer觀察的數據發生變化時,通過Dep通知各個已經訂閱的Watcher。

Watcher是用來訂閱數據的變化的并執行相應操作(例如更新視圖)的。Watcher的構造器函數定義如下:

參數中,vm表示組件實例,expOrFn表示要訂閱的數據字段(字符串表示,例如a.b.c)或是一個要執行的函數,cb表示watcher運行后的回調函數,options是選項對象,包含deep、user、lazy等配置。

Object.defineProperty(obj, prop, descriptor) ,這個語法內有三個參數,分別為 obj (要定義屬性的對象) prop (要定義或修改的屬性的名稱或 Symbol ) descriptor (要定義或修改的屬性描述符=>具體的改變方法)

簡單地說,就是用這個方法來定義一個值。當調用時我們使用了它里面的get方法,當我們給這個屬性賦值時,又用到了它里面的set方法;

主要解釋第三個參數 {

value: 設置屬性的值

writable: 值是否可以重寫。true | false

enumerable: 目標屬

很赞哦!(9)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款的名片

职业:程序员,设计师

现居:河南洛阳洛龙区

工作室:小组

Email:[email protected]