国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

@angular/forms 源碼解析之雙向綁定

yangrd / 637人閱讀

摘要:由于的屬性提供了令牌,并且該令牌指向的對象就是,所以構造函數中注入的令牌包含的對象數組只有一個。這樣的構造函數里就會包含一個對象,然后把這個傳給對象,最后注冊回調,這樣以后值更新時就會運行。整個包的設計也是按照這種數據流形式,并不復雜。

我們知道,Angular 的 @angular/forms 包提供了 NgModel 指令,來實現雙向綁定,即把一個 JS 變量(假設為 name)與一個 DOM 元素(假設為 input 元素)進行綁定,這樣 name 的值發生變化,input 元素 的 value 也會自動變化;input 元素的 value 發生變化,name 的值也會自動變化。如下代碼,展示一個最簡單的雙向綁定(也可見 stackblitz demo):

@Component({
  selector: "my-app",
  template: `
    
    
    

{{name}}

`, styleUrls: [ "./app.component.css" ] }) export class AppComponent { name = "banana"; }

上面代碼使用了 NgModel 指令來把變量 nameinput DOM 元素雙向綁定到了一起,這里為了更清晰理解 NgModel 的本質,沒有使用 [(ngModel)] 語法糖。實際上,在模板里寫 [(xxx)] 這種 "BANANA_BOX" 語法,@angular/compiler 的 Template Parser 會把這種語法拆解為為 [xxx](xxxChange),可看 L448-L453L501-L505,所以 [(xxx)] 僅僅是為了省事的簡單寫法。

查看 stackblitz demo 可以看到,如果修改 input 里的值,name 變量的值也自動發生變化了,這點可從與 name 綁定的 p 標簽值自動變化看出;如果點擊 button 修改了 name 的值,input 輸入框內的 value 值也發生變化了,這點可從 input 框內的值變化可看到。那 NgModel 指令是如何做到雙向綁定的呢?

在理解 NgModel 指令雙向綁定原理之前,可以先看看雙向綁定最簡單形式:



Hello {{country}}!

點擊 button 修改 model 時,就會自動修改 input 的 value 值,即自動修改 view,數據流方向就是 model -> view;更新 input 框內值時,就會自動修改 country 這個 model 值,這點可從綁定的 p 標簽看到,這時數據流方向就是 view -> model。當然,這是最簡單且最不可擴展的一個雙向綁定實例,如果去設計一個指令,不僅僅需要考慮 view 的不同類型,而且還需要考慮數據校驗問題。盡管如此,這個簡單實例與 NgModel 指令本質是類似的。

如果自己設計這樣一個雙向綁定指令,那它的輸入必然是綁定的變量 name,該指令接收 name 后再去更新 input 元素的 value 值(還得支持 textarea,select 等 DOM 元素,甚至組件等自定義 DOM 元素),這樣 name 發生變化,input 的 value 也會自動變化,即 model -> view;輸出的必然是 input 元素的 value 值,然后賦值給 name,這樣 input 元素的值變化,name 值也自動變化,即 view -> model。這里的最難點是該指令得能夠寫 DOM 元素(不管原生或者自定義 DOM 元素)的值,并且能夠監聽 DOM 元素的值變化,讀取變化的值。 所以,為了支持原生 DOM 元素或自定義 DOM 元素,為了有個好的設計模式,必然會抽象出一個接口,來幫助指令去寫入和監聽讀取 DOM 元素值,有了這個接口,事情就簡單很多了。

現在,我們需要搞明白兩個問題:name 值發生變化時,input 的 value 如何自動變化;input 的 value 變化,name 值如何自動變化?

綁定到 input 上的 NgModel 指令在實例化時,其 構造函數 會首先查找出 ControlValueAccessor 對象,這個 ControlValueAccessor 就是上文提到的抽象出來的對象,該對象會具體負責更新和監聽讀取 DOM 元素的值。上文模板中的 input 元素不僅僅綁定了 NgModel 指令,實際上還綁定了 DefaultValueAccessor 指令,這點可以從該指令的選擇器知道,如果 input 模板是這么寫的:

那不僅僅綁定了 DefaultValueAccessor 指令,還綁定了 NumberValueAccessor 指令。

由于 DefaultValueAccessor 的 providers 屬性提供了 NG_VALUE_ACCESSOR 令牌,并且該令牌指向的對象就是 DefaultValueAccessor,所以 NgModel 構造函數中注入的 NG_VALUE_ACCESSOR 令牌包含的 ControlValueAccessor 對象數組只有 DefaultValueAccessor 一個。如果是 type="number" 的 input,則 valueAccessors 包含 NumberValueAccessorDefaultValueAccessor 這兩個對象。構造函數中的 selectValueAccessor() 方法會依次遍歷 NG_VALUE_ACCESSOR 令牌提供的 ControlValueAccessor 對象數組,如果是自定義的 ControlValueAccessor 優先選擇自定義的,如果是 @angular/forms 內置的 ControlValueAccessor 就選擇內置的(內置的也就 6 個),否則最后選擇默認的 ControlValueAccessorDefaultValueAccessor 對象。對于本文 demo,那就是默認的 DefaultValueAccessor 對象。注意的一點是,注入的 NG_VALUE_ACCESSOR 令牌有裝飾器 @Self,所以只能從自身去查找這個依賴,自身的意思是 NgModel 指令自己,和它一起掛載到 input 元素的其他指令。另外,input 上沒有綁定任何 validators 指令,所以注入的 NG_VALIDATORS 和 NG_ASYNC_VALIDATORS 令牌解析的值為空,并且 input 多帶帶使用,沒有放在 form 元素內,或 FormGroup 綁定的元素內,所以不存在宿主控件容器 ControlContainer,即 parent 也為空。

NgModel 指令在首次實例化時,運行 _setUpControl() 方法,利用 ControlValueAccessor(本 demo 即 DefaultValueAccessor 對象) 把 NgModel 指令內部的 FormControl 對象與 DOM 元素綁定。由于本 demo 中,NgModel 指令綁定的 input 沒有父控件容器,所以會調用 _setUpStandalone 方法,核心方法就是 setUpControl(),該方法主要包含兩點:第一點,通過調用 setUpViewChangePipeline()DefaultValueAccessor 對象內注冊一個回調函數,這樣當 input 值發生變化時,就觸發 input 事件 時,會執行這個回調函數,而這個回調函數的邏輯 一是更新 FormControl 的 value,二是讓 NgModel 指令拋出 ngModelChange 事件,該事件包含的值就是當前 input 變化的新值,所以,setUpViewChangePipeline() 方法的作用就是搭建了 view -> model 的管道,這樣 view (這里是 input) 值發生變化時,會同步 FormControl 對象的 value 值,并讓 NgModel 指令把這個新值輸出出去;第二點,通過調用 setUpModelChangePipeline 方法向 FormControl 對象內注冊 一個回調,這個回調邏輯是當 FormControl 的 value 值發生變化時(本 demo 中就是 [ngModel]="name" 時,name 值發生變化,也就是屬性值改變,這樣 isPropertyUpdated(changes, this.viewModel) 就為 true,這樣就會需要更新 FormControl 的 value 值 FormControl.setValue(value),從而會 觸發 上文說的 FormControl 對象內的回調函數),通過調用 ControlValueAccessor.writeValue() 方法去修改 view (這里是 input) 的 value 值(本 demo 中使用的是 DefaultValueAccessor.writeValue(value)),然后讓 NgModel 指令拋出 ngModelChange 事件,該事件包含的值就是當前 FormControl 對象 變化的新值,所以,setUpModelChangePipeline() 方法的作用就是搭建了 model -> view 的管道,這樣 FormControl 對象值發生改變時,會同步更新 view 的 value,并讓 NgModel 指令把這個新值輸出出去。

通過以上的解釋,就能理解 name 值發生變化時,input 的 value 是如何自動變化的;input 的 value 發生變化時,name 值是如何自動變化的。(最好能一個個點擊鏈接查看源碼,效率更高。) 一句話解釋就是:NgModel 指令初始化時先安裝了兩個回調(一個是 view 變化時更新 FormControl 對象 value 值的回調,另一個是 FormControl 對象 value 值變化時更新 view 值的回調),數據流方向從 view -> model 時,更新 FormControl 對象并拋出攜帶該值的 ngModelChange 事件,數據流方向從 model -> view 時,利用 ControlValueAccessor 去更新 view 值,同時也拋出攜帶該值的 ngModelChange 事件。拋出的 ngModelChange 事件包含新值,模板中的 $event 會被 @angular/compiler 特殊處理,為 ngModelChange 事件拋出的值。

當然,本文沒有考慮存在 Validators 的情況,如果 input 模板修改為如下代碼:

那該模板除了綁定 NgModel 指令外,還綁定了 RequiredValidator 指令,這樣不管數據流方向是 view -> model 還是 model -> view,在數據流動之前,還需要運行驗證器,驗證數據的有效性。這樣 NgModel 的構造函數里就會包含 一個 RequiredValidator 對象,然后 把這個 Validator 傳給 FormControl 對象,最后注冊 validatorChange 回調,這樣以后 FormControl 值更新時就會 運行 Validators

總之,NgModel 指令來管理 model <-> view 的數據流,內部存在一個 FormControl 對象,用來讀取存儲值和驗證有效性,從 FormControl 讀取的值會賦值給外界傳進來的 model,view 是借助 ControlValueAccessor 來讀寫值。整個 @angular/forms 包的設計也是按照這種數據流形式,并不復雜。

也可閱讀 @angular/forms 相關文章了解如何寫一個自定義的 ControlValueAccessor:譯 別再對 Angular 表單的 ControlValueAccessor 感到迷惑

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96510.html

相關文章

  • @angular/forms 源碼解析 Validators

    摘要:校驗器運行完成后,會設置屬性,從而計算的屬性,假設校驗錯誤,則屬性值為。這樣就理解了校驗器的整個運行過程,也包括為何校驗錯誤時會自動添加描述控件狀態的。 我們知道,@angular/forms 包主要用來解決表單問題的,而表單問題非常重要的一個功能就是表單校驗功能。數據校驗非常重要,不僅僅前端在發請求給后端前需要校驗數據,后端對前端發來的數據也需要校驗其有效性和邏輯性,尤其在存入數據庫...

    JowayYoung 評論0 收藏0
  • ANGULAR2 與 D3.js集成實現自定義可視化

    摘要:目標展現層與邏輯層分離數據與可視化組件相分離數據與視圖雙向綁定實時更新代碼結構清晰易于維護與修改基本原理的組件生命周期鉤子方法父子組件交互機制模板語法源碼解析代碼結構很簡單,其中除主頁和之外的代碼結構如下所示實現宿主視圖定義,個按鈕,按鈕 目標 展現層與邏輯層分離 數據與可視化組件相分離 數據與視圖雙向綁定,實時更新 代碼結構清晰,易于維護與修改 基本原理 angular2 的組件...

    wangbjun 評論0 收藏0
  • Angular 4 簡單入門筆記

    摘要:首先,我們需要在入口頁面的中配置根路徑然后創建一個路由模塊路由配置在主模塊中導入配置好的路由模塊而在頁面中需要一個容器去承載上面代碼中的定義了用戶點擊后的路由跳轉,定義該路由激活時的樣式類。 剛實習的時候用過AngularJS,那時候真的是連原生JavaScript都不會寫,依樣畫葫蘆做了幾個管理后臺。然后突然換項目了,AngularJS就不寫了,感覺前前后后接觸了一年多的Angula...

    whlong 評論0 收藏0
  • angular2初入眼簾-多components協作

    摘要:我們使用了模式書寫,并引入了思想,這些以前只在里見到的設計,現在里也有體現,并且在本章中會著重講解多的協作。如果之前寫過,那對于這種書寫方式一定無比熟悉。每次數據的變更,無論是還是,都將變化冒泡到,然后由再向下逐級推送各組件是否重繪。 前集回顧 在上一章里我們講了如何在angular2下開發一個component(還沒做的趕緊去學吧)。我們使用了Unidirectional Data ...

    dreamans 評論0 收藏0
  • angular4 學習記錄 -- 表單

    摘要:在表單上添加的會攔截標準的表單提交事件。并為它們提供了一些共同的行為和屬性,其中有些是可觀察對象。用于跟蹤一個單獨的表單控件的值和有效性狀態。組件中的頂級表單就是一個。在表單所在的中的上添加,再在指定的驗證方法中調用來顯示驗證失敗信息。 angular4 表單 模板表單 在app.module中導入FormsModule之后,項目中的form表單都會是一個ngForm,也就是一個模板表...

    james 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<