国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

[譯]AngularDOM更新機制-Laravel/Angular技術分享

來源:懂視網 責編:小采 時間:2020-11-27 19:31:36
文檔

[譯]AngularDOM更新機制-Laravel/Angular技術分享

[譯]AngularDOM更新機制-Laravel/Angular技術分享:本篇文章主要的向大家介紹了angularjs dom的更新機制,還有關于angularjs的模型表達式和程序內部架構等很多知識點,下面就讓我們一起開始學習吧angularjs的模型表達式:由模型變化觸發的 DOM 更新是所有前端框架的重要功能(注:即保持 model 和 vi
推薦度:
導讀[譯]AngularDOM更新機制-Laravel/Angular技術分享:本篇文章主要的向大家介紹了angularjs dom的更新機制,還有關于angularjs的模型表達式和程序內部架構等很多知識點,下面就讓我們一起開始學習吧angularjs的模型表達式:由模型變化觸發的 DOM 更新是所有前端框架的重要功能(注:即保持 model 和 vi

angularjs的模型表達式:

由模型變化觸發的 DOM 更新是所有前端框架的重要功能(注:即保持 model 和 view 的同步),當然 Angular 也不例外。定義一個如下模板表達式:

<span>Hello {{name}}</span>

或者類似下面的屬性綁定(注:這與上面代碼等價):

<span [textContent]="'Hello ' + name"></span>

當每次 name 值發生變化時,Angular 會神奇般的自動更新 DOM 元素(注:最上面代碼是更新 DOM 文本節點,上面代碼是更新 DOM 元素節點,兩者是不一樣的,下文解釋)。這表面上看起來很簡單,但是其內部工作相當復雜。而且,DOM 更新僅僅是 Angular 變更檢測機制 的一部分,變更檢測機制主要由以下三步組成:

  • DOM updates(注:即本文將要解釋的內容)

  • child components Input bindings updates

  • query list updates

  • 本文主要探索變更檢測機制的渲染部分(即 DOM updates 部分)。如果你之前也對這個問題很好奇,可以繼續讀下去,絕對讓你茅塞頓開。

    在引用相關源碼時,假設程序是以生產模式運行。讓我們開始吧!

    程序內部架構

    在探索 DOM 更新之前,我們先搞清楚 Angular 程序內部究竟是如何設計的,簡單回顧下吧。

    視圖

    從我的這篇文章 Here is what you need to know about dynamic components in Angular 知道 Angular 編譯器會把程序中使用的組件編譯為一個工廠類(factory)。例如,下面代碼展示 Angular 如何從工廠類中創建一個組件(注:這里作者邏輯貌似有點亂,前一句說的 Angular 編譯器編譯的工廠類,其實是編譯器去做的,不需要開發者做任何事情,是自動化的事情;而下面代碼說的是開發者如何手動通過 ComponentFactory 來創建一個 Component 實例。總之,他是想說組件是怎么被實例化的):

    const factory = r.resolveComponentFactory(AComponent);
    componentRef: ComponentRef<AComponent> = factory.create(injector);

    Angular 使用這個工廠類來實例化 View Definition ,然后使用 viewDef 函數來 創建視圖。Angular 內部把一個程序看作為一顆視圖樹,一個程序雖然有眾多組件,但有一個公共的視圖定義接口來定義由組件生成的視圖結構(注:即 ViewDefinition Interface),當然 Angular 使用每一個組件對象來創建對應的視圖,從而由多個視圖組成視圖樹。(注:這里有一個主要概念就是視圖,其結構就是 ViewDefinition Interface)

    組件工廠

    組件工廠大部分代碼是由編譯器生成的不同視圖節點組成的,這些視圖節點是通過模板解析生成的(注:編譯器生成的組件工廠是一個返回值為函數的函數,上文的 ComponentFactory 是 Angular 提供的類,供手動調用。當然,兩者指向同一個事物,只是表現形式不同而已)。假設定義一個組件的模板如下:

    <span>I am {{name}}</span>

    編譯器會解析這個模板生成包含如下類似的組件工廠代碼(注:這只是最重要的部分代碼):

    function View_AComponent_0(l) {
     return jit_viewDef1(0,
     [
     jit_elementDef2(0,null,null,1,'span',...),
     jit_textDef3(null,['I am ',...])
     ], 
     null,
     function(_ck,_v) {
     var _co = _v.component;
     var currVal_0 = _co.name;
     _ck(_v,1,0,currVal_0);
    注:由 AppComponent 組件編譯生成的工廠函數完整代碼如下
     (function(jit_createRendererType2_0,jit_viewDef_1,jit_elementDef_2,jit_textDef_3) {
     var styles_AppComponent = [''];
     var RenderType_AppComponent = jit_createRendererType2_0({encapsulation:0,styles:styles_AppComponent,data:{}});
     function View_AppComponent_0(_l) {
     return jit_viewDef_1(0,
     [
     (_l()(),jit_elementDef_2(0,0,null,null,1,'span',[],null,null,null,null,null)),
     (_l()(),jit_textDef_3(1,null,['I am ','']))
     ],
     null,
     function(_ck,_v) {
     var _co = _v.component;
     var currVal_0 = _co.name;
     _ck(_v,1,0,currVal_0);
     });
     }
     return {RenderType_AppComponent:RenderType_AppComponent,View_AppComponent_0:View_AppComponent_0};})

    上面代碼描述了視圖的結構,并在實例化組件時會被調用。jit_viewDef_1 其實就是 viewDef 函數,用來創建視圖(注:viewDef 函數很重要,因為視圖是調用它創建的,生成的視圖結構即是 ViewDefinition)。

    viewDef 函數的第二個參數 nodes 有些類似 html 中節點的意思,但卻不僅僅如此。上面代碼中第二個參數是一個數組,其第一個數組元素 jit_elementDef_2 是元素節點定義,第二個數組元素 jit_textDef_3 是文本節點定義。Angular 編譯器會生成很多不同的節點定義,節點類型是由 NodeFlags 設置的。稍后我們將看到 Angular 如何根據不同節點類型來做 DOM 更新。

    本文只對元素和文本節點感興趣:

    export const enum NodeFlags {
     TypeElement = 1 << 0, 
     TypeText = 1 << 1

    讓我們簡要擼一遍。

    注:上文作者說了一大段,其實核心就是,程序是一堆視圖組成的,而每一個視圖又是由不同類型節點組成的。而本文只關心元素節點和文本節點,至于還有個重要的指令節點在另一篇文章。

    元素節點的結構定義

    元素節點結構 是 Angular 編譯每一個 html 元素生成的節點結構,它也是用來生成組件的,如對這點感興趣可查看 Here is why you will not find components inside Angular。元素節點也可以包含其他元素節點和文本節點作為子節點,子節點數量是由 childCount 設置的。

    所有元素定義是由 elementRef 函數生成的,而工廠函數中的 jit_elementDef_2() 就是這個函數。elementRef() 主要有以下幾個一般性參數:

    NameDescription
    childCountspecifies how many children the current element have
    namespaceAndNamethe name of the html element(注:如 'span')
    fixedAttrsattributes defined on the element

    還有其他的幾個具有特定性能的參數:

    NameDescription
    matchedQueriesDslused when querying child nodes
    ngContentIndexused for node projection
    bindingsused for dom and bound properties update
    outputs, handleEventused for event propagation

    本文主要對 bindings 感興趣。

    注:從上文知道視圖(view)是由不同類型節點(nodes)組成的,而元素節點(element nodes)是由 elementRef 函數生成的,元素節點的結構是由 ElementDef 定義的。

    文本節點的結構定義

    文本節點結構 是 Angular 編譯每一個 html 文本 生成的節點結構。通常它是元素定義節點的子節點,就像我們本文的示例那樣(注:<span>I am {{name}}</span>span 是元素節點,I am {{name}} 是文本節點,也是 span 的子節點)。這個文本節點是由 textDef 函數生成的。它的第二個參數以字符串數組形式傳進來(注: Angular v5.* 是第三個參數)。例如,下面的文本:

    <h1>Hello {{name}} and another {{prop}}</h1>

    將要被解析為一個數組:

    ["Hello ", " and another ", ""]

    然后被用來生成正確的綁定:

    {
     text: 'Hello',
     bindings: [
     {
     name: 'name',
     suffix: ' and another '
     },
     {
     name: 'prop',
     suffix: ''
     }
     ]
    }

    在臟檢查(注:即變更檢測)階段會這么用來生成文本:

    text
    + context[bindings[0][property]] + context[bindings[0][suffix]]
    + context[bindings[1][property]] + context[bindings[1][suffix]]
    注:同上,文本節點是由 textDef 函數生成的,結構是由 TextDef 定義的。既然已經知道了兩個節點的定義和生成,那節點上的屬性綁定, Angular 是怎么處理的呢?

    節點的綁定

    Angular 使用 BindingDef 來定義每一個節點的綁定依賴,而這些綁定依賴通常是組件類的屬性。在變更檢測時 Angular 會根據這些綁定來決定如何更新節點和提供上下文信息。具體哪一種操作是由 BindingFlags 決定的,下面列表展示了具體的 DOM 操作類型:

    NameConstruction in template
    TypeElementAttributeattr.name
    TypeElementClassclass.name
    TypeElementStylestyle.name

    元素和文本定義根據這些編譯器可識別的綁定標志位,內部創建這些綁定依賴。每一種節點類型都有著不同的綁定生成邏輯(注:意思是 Angular 會根據 BindingFlags 來生成對應的 BindingDef)。(想看更多就到PHP中文網AngularJS開發手冊中學習)

    更新渲染器

    最讓我們感興趣的是 jit_viewDef_1 中最后那個參數:

    function(_ck,_v) {
     var _co = _v.component;
     var currVal_0 = _co.name;
     _ck(_v,1,0,currVal_0);
    });

    這個函數叫做 updateRenderer。它接收兩個參數:_ck_v_ckcheck 的簡寫,其實就是 prodCheckAndUpdateNode 函數,而 _v 就是當前視圖對象。updateRenderer 函數會在 每一次變更檢測時 被調用,其參數 _ck_v 也是這時被傳入。

    updateRenderer 函數邏輯主要是,從組件對象的綁定屬性獲取當前值,并調用 _ck 函數,同時傳入視圖對象、視圖節點索引和綁定屬性當前值。重要一點是 Angular 會為每一個視圖執行 DOM 更新操作,所以必須傳入視圖節點索引參數(注:這個很好理解,上文說了 Angular 會依次對每一個 view 做模型視圖同步過程)。你可以清晰看到 _ck 參數列表:

    function prodCheckAndUpdateNode(
     view: ViewData, 
     nodeIndex: number, 
     argStyle: ArgumentType, 
     v0?: any, 
     v1?: any, 
     v2?: any,

    nodeIndex 是視圖節點的索引,如果你模板中有多個表達式:

    <h1>Hello {{name}}</h1>
    <h1>Hello {{age}}</h1>

    編譯器生成的 updateRenderer 函數如下:

    var _co = _v.component;
    
    // here node index is 1 and property is `name`
    var currVal_0 = _co.name;
    _ck(_v,1,0,currVal_0);
    
    // here node index is 4 and bound property is `age`
    var currVal_1 = _co.age;
    _ck(_v,4,0,currVal_1);

    更新 DOM

    現在我們已經知道 Angular 編譯器生成的所有對象(注:已經有了 view,element node,text node 和 updateRenderer 這幾個道具),現在我們可以探索如何使用這些對象來更新 DOM。

    從上文我們知道變更檢測期間 updateRenderer 函數傳入的一個參數是 _ck 函數,而這個函數就是 prodCheckAndUpdateNode。這個函數在繼續執行后,最終會調用 checkAndUpdateNodeInline ,如果綁定屬性的數量超過 10,Angular 還提供了 checkAndUpdateNodeDynamic 這個函數(注:兩個函數本質一樣)。

    checkAndUpdateNodeInline 函數會根據不同視圖節點類型來執行對應的檢查更新函數:

    case NodeFlags.TypeElement -> checkAndUpdateElementInline
    case NodeFlags.TypeText -> checkAndUpdateTextInline
    case NodeFlags.TypeDirective -> checkAndUpdateDirectiveInline

    讓我們看下這些函數是做什么的,至于 NodeFlags.TypeDirective 可以查看我寫的文章 The mechanics of property bindings update in Angular 。

    注:因為本文只關注 element node 和 text node

    元素節點

    對于元素節點,會調用函數 checkAndUpdateElementInline 以及 checkAndUpdateElementValue,checkAndUpdateElementValue 函數會檢查綁定形式是否是 [attr.name, class.name, style.some] 或是屬性綁定形式:

    case BindingFlags.TypeElementAttribute -> setElementAttribute
    case BindingFlags.TypeElementClass -> setElementClass
    case BindingFlags.TypeElementStyle -> setElementStyle
    case BindingFlags.TypeProperty -> setElementProperty;

    然后使用渲染器對應的方法來對該節點執行對應操作,比如使用 setElementClass 給當前節點 span 添加一個 class

    文本節點

    對于文本節點類型,會調用 checkAndUpdateTextInline ,下面是主要部分:

    if (checkAndUpdateBinding(view, nodeDef, bindingIndex, newValue)) {
     value = text + _addInterpolationPart(...);
     view.renderer.setValue(DOMNode, value);
    }

    它會拿到 updateRenderer 函數傳過來的當前值(注:即上文的 _ck(_v,4,0,currVal_1);),與上一次變更檢測時的值相比較。視圖數據包含有 oldValues 屬性,如果屬性值如 name 發生變化,Angular 會使用最新 name 值合成最新的字符串文本,如 Hello New World,然后使用渲染器更新 DOM 上對應的文本。(想看更多就到PHP中文網AngularJS開發手冊中學習)

    注:更新元素節點和文本節點都提到了渲染器(renderer),這也是一個重要的概念。每一個視圖對象都有一個 renderer 屬性,即是 Renderer2 的引用,也就是組件渲染器,DOM 的實際更新操作由它完成。因為 Angular 是跨平臺的,這個 Renderer2 是個接口,這樣根據不同 Platform 就選擇不同的 Renderer。比如,在瀏覽器里這個 Renderer 就是 DOMRenderer,在服務端就是 ServerRenderer,等等。從這里可看出,Angular 框架設計做了很好的抽象。

    結論

    我知道有大量難懂的信息需要消化,但是只要理解了這些知識,你就可以更好的設計程序或者去調試 DOM 更新相關的問題。我建議你按照本文提到的源碼邏輯,使用調試器或 debugger 語句 一步步去調試源碼。

    好了,本篇文章到這就結束了(想看更多就到PHP中文網AngularJS使用手冊中學習),有問題的可以在下方留言提問。

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    [譯]AngularDOM更新機制-Laravel/Angular技術分享

    [譯]AngularDOM更新機制-Laravel/Angular技術分享:本篇文章主要的向大家介紹了angularjs dom的更新機制,還有關于angularjs的模型表達式和程序內部架構等很多知識點,下面就讓我們一起開始學習吧angularjs的模型表達式:由模型變化觸發的 DOM 更新是所有前端框架的重要功能(注:即保持 model 和 vi
    推薦度:
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 欧美日韩免费电影 | 中文字幕日韩精品有码视频 | 国产成人综合一区精品 | 欧美伊香蕉久久综合类网站 | 97国产精品欧美一区二区三区 | 亚洲欧美日韩第一页 | 国产日韩亚洲欧美 | 日韩欧美一区二区三区在线播放 | 国产一区二区三区成人久久片 | 一级毛片一级毛片一级级毛片 | 五月婷综合 | 精品国产系列 | 自拍 欧美 日韩 | 亚洲一区中文字幕在线 | 亚洲精品不卡久久久久久 | 亚洲日本乱码中文论理在线电影 | 国产欧美在线观看一区二区 | 欧美日韩国产另类一区二区三区 | 销魂美女一区二区 | 亚洲欧美中文字幕 | 久久99精品久久久久久 | 欧美 日韩 中文字幕 | 欧美日韩国产精品 | 欧美一区二区日韩一区二区 | 国产精品一区二区三区高清在线 | 看全色黄大色大片免费久久久 | 欧美综合国产 | 欧美日本综合 | 亚洲一区二区免费看 | 国产视频在 | 久久伊人网视频 | 国产一区二区三区免费视频 | 国产在线欧美日韩精品一区二区 | 精品国产一区二区三区香蕉 | 三级网站免费播放国语 | 欧美日韩亚洲视频 | 日韩成人在线免费视频 | 自拍偷拍欧美亚洲 | 久久久久成人精品一区二区 | 伊人精品久久久大香线蕉99 | 欧美高清在线精品一区二区不卡 |