国产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
當前位置: 首頁 - 科技 - 知識百科 - 正文

[譯]Angular屬性綁定更新機制-Laravel/Angular技術分享

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

[譯]Angular屬性綁定更新機制-Laravel/Angular技術分享

[譯]Angular屬性綁定更新機制-Laravel/Angular技術分享:本篇文章主要的講述了關于angularjs屬性綁定更新機制,還有angularjs更新屬性的詳解,都在這篇文章中,現在就讓我們一起來看這篇文章吧angularjs屬性綁定更新機制解釋:所有現代前端框架都是用組件來合成 UI,這樣很自然就會產生父子組件層級,這就需要框架提
推薦度:
導讀[譯]Angular屬性綁定更新機制-Laravel/Angular技術分享:本篇文章主要的講述了關于angularjs屬性綁定更新機制,還有angularjs更新屬性的詳解,都在這篇文章中,現在就讓我們一起來看這篇文章吧angularjs屬性綁定更新機制解釋:所有現代前端框架都是用組件來合成 UI,這樣很自然就會產生父子組件層級,這就需要框架提

angularjs屬性綁定更新機制解釋:

所有現代前端框架都是用組件來合成 UI,這樣很自然就會產生父子組件層級,這就需要框架提供父子組件通信的機制。同樣,Angular 也提供了兩種方式來實現父子組件通信:輸入輸出綁定和共享服務。對于 stateless presentational components 我更喜歡輸入輸出綁定方式,然而對于 stateful container components 我使用共享服務方式。

本文主要介紹輸入輸出綁定方式,特別是當父組件輸入綁定值變化時,Angular 如何更新子組件輸入值。如果想了解 Angular 如何更新當前組件 DOM,可以查看 譯 Angular DOM 更新機制,這篇文章也會有助于加深對本文的理解。由于我們將探索 Angular 如何更新 DOM 元素和組件的輸入綁定屬性,所以假定你知道 Angular 內部是如何表現組件和指令的,如果你不是很了解并且很感興趣,可以查看 譯 為何 Angular 內部沒有發現組件, 這篇文章主要講了 Angular 內部如何使用指令形式來表示組件。而本文對于組件和指令兩個概念互換使用,因為 Angular 內部就是把組件當做指令。

模板綁定語法

你可能知道 Angular 提供了 屬性綁定語法 —— [],這個語法很通用,它可以用在子組件上,也可以用在原生 DOM 元素上。如果你想從父組件把數據傳給子組件 b-comp 或者原生 DOM 元素 span,你可以在父組件模板中這么寫:

import { Component } from '@angular/core';

@Component({
 moduleId: module.id,
 selector: 'a-comp',
 template: `
 <b-comp [textContent]="AText"></b-comp>
 <span [textContent]="AText"></span>
 `
})
export class AComponent {
 AText = 'some';
}

你不必為原生 DOM 元素做些額外的工作,但是對于子組件 b-comp 你需要申明輸入屬性 textContent

@Component({
 selector: 'b-comp',
 template: 'Comes from parent: {{textContent}}'
})
export class BComponent {
 @Input() textContent;
}

這樣當父組件 AComponent.AText 屬性改變時,Angular 會自動更新子組件 BComponent.textContent 屬性,和原生元素 span.textContent 屬性。同時,還會調用子組件 BComponent 的生命周期鉤子函數 ngOnChanges(注:實際上還有 ngDoCheck,見下文)。

你可能好奇 Angular 是怎么知道 BComponentspan 支持 textContent 綁定的。這是因為 Angular 編譯器在解析模板時,如果遇到簡單 DOM 元素如 span,就去查找這個元素是否定義在 dom_element_schema_registry,從而知道它是 HTMLElement 子類,textContent 是其中的一個屬性(注:可以試試如果 span 綁定一個 [abc]=AText 就報錯,沒法識別 abc 屬性);如果遇到了組件或指令,就去查看其裝飾器 @Component/@Directive 的元數據 input 屬性里是否有該綁定屬性項,如果沒有,編譯器同樣會拋出錯誤:

Can’t bind to ‘textContent’ since it isn’t a known property of …

這些知識都很好理解,現在讓我們進一步看看其內部發生了什么。

組件工廠

盡管在子組件 BComponentspan 元素綁定了輸入屬性,但是輸入綁定更新所需要的信息全部在父組件 AComponent 的組件工廠里。讓我們看下 AComponent 的組件工廠代碼:

function View_AComponent_0(_l) {
 return jit_viewDef1(0, [
 jit_elementDef_2(..., 'b-comp', ...),
 jit_directiveDef_5(..., jit_BComponent6, [], {
 textContent: [0, 'textContent']
 }, ...),
 jit_elementDef_2(..., 'span', [], [[8, 'textContent', 0]], ...)
 ], function (_ck, _v) {
 var _co = _v.component;
 var currVal_0 = _co.AText;
 var currVal_1 = 'd';
 _ck(_v, 1, 0, currVal_0, currVal_1);
 }, function (_ck, _v) {
 var _co = _v.component;
 var currVal_2 = _co.AText;
 _ck(_v, 2, 0, currVal_2);
 });
}

如果你讀了 譯 Angular DOM 更新機制 或 譯 為何 Angular 內部沒有發現組件,就會對上面代碼中的各個視圖節點比較熟悉了。前兩個節點中,jit_elementDef_2 是元素節點,jit_directiveDef_5 是指令節點,這兩個組成了子組件 BComponent;第三個節點 jit_elementDef_2 也是元素節點,組成了 span 元素。(想看更多就到PHP中文網AngularJS開發手冊中學習)

節點綁定

相同類型的節點使用相同的節點定義函數,但區別是接收的參數不同,比如 jit_directiveDef_5 節點定義函數參數如下:

jit_directiveDef_5(..., jit_BComponent6, [], {
 textContent: [0, 'textContent']
}, ...),

其中,參數 {textContent: [0, 'textContent']} 叫做 props,這點可以查看 directiveDef 函數的參數列表:

directiveDef(..., props?: {[name: string]: [number, string]}, ...)

props 參數是一個對象,每一個鍵為綁定屬性名,對應的值為綁定索引和綁定屬性名組成的數組,比如本例中只有一個綁定,textContent 對應的值為:

{textContent: [0, 'textContent']}

如果指令有多個綁定,比如:

<b-comp [textContent]="AText" [otherProp]="AProp">

props 參數值也包含兩個屬性:

jit_directiveDef5(49152, null, 0, jit_BComponent6, [], {
 textContent: [0, 'textContent'],
 otherProp: [1, 'otherProp']
}, null),

Angular 會使用這些值來生成當前指令節點的 binding,從而生成當前視圖的指令節點。在變更檢測時,每一個 binding 決定 Angular 使用哪種操作來更新節點和提供上下文信息,綁定類型是通過 BindingFlags 設置的(注:每一個綁定定義是 BindingDef,它的屬性 flags: BindingFlags 決定 Angular 該采取什么操作,比如 Class 型綁定和 Style 型綁定都會調用對應的操作函數,見下文)。比如,如果是屬性綁定,編譯器會設置綁定標志位為:

export const enum BindingFlags {
 TypeProperty = 1 << 3,
注:上文說完了指令定義函數的參數,下面說說元素定義函數的參數。

本例中,因為 span 元素有屬性綁定,編譯器會設置綁定參數為 [[8, 'textContent', 0]]

jit_elementDef2(..., 'span', [], [[8, 'textContent', 0]], ...)

不同于指令節點,對元素節點來說,綁定參數結構是個二維數組,因為 span 元素只有一個綁定,所以它僅僅只有一個子數組。數組 [8, 'textContent', 0] 中第一個參數也同樣是綁定標志位 BindingFlags,決定 Angular 應該采取什么類型操作(注:[8, 'textContent', 0] 中的 8 表示為 property 型綁定):

export const enum BindingFlags {
 TypeProperty = 1 << 3, // 8

其他類型標志位已經在文章 譯 Angular DOM 更新機制 有所解釋:

TypeElementAttribute = 1 << 0,
TypeElementClass = 1 << 1,
TypeElementStyle = 1 << 2,

編譯器不會為指令定義提供綁定標志位,因為指令的綁定類型也只能是 BindingFlags.TypeProperty

注:節點綁定 這一節主要講的是對于元素節點來說,每一個節點的 binding 類型是由 BindingFlags 決定的;對于指令節點來說,每一個節點的 binding 類型只能是 BindingFlags.TypeProperty

updateRenderer 和 updateDirectives

組件工廠代碼里,編譯器還為我們生成了兩個函數:

function (_ck, _v) {
 var _co = _v.component;
 var currVal_0 = _co.AText;
 var currVal_1 = _co.AProp;
 _ck(_v, 1, 0, currVal_0, currVal_1);
},
function (_ck, _v) {
 var _co = _v.component;
 var currVal_2 = _co.AText;
 _ck(_v, 2, 0, currVal_2);
}

如果你讀了 譯 Angular DOM 更新機制,應該對第二個函數即 updateRenderer 有所熟悉。第一個函數叫做 updateDirectives。這兩個函數都是 ViewUpdateFn 類型接口,兩者都是視圖定義的屬性:

interface ViewDefinition {
 flags: ViewFlags;
 updateDirectives: ViewUpdateFn;
 updateRenderer: ViewUpdateFn;

有趣的是這兩個函數的函數體基本相同,參數都是 _ck_v,并且兩個函數的對應參數都指向同一個對象,所以為何需要兩個函數?

因為在變更檢測期間,這是不同階段的兩個不同行為:

  • 更新子組件的輸入綁定屬性

  • 更新當前組件的 DOM 元素

  • 這兩個操作是在變更檢測的不同階段執行,所以 Angular 需要兩個獨立的函數分別在對應的階段調用:

  • updateDirectives——變更檢測的開始階段被調用,來更新子組件的輸入綁定屬性

  • updateRenderer——變更檢測的中間階段被調用,來更新當前組件的 DOM 元素

  • 這兩個函數都會在 Angular 每次的變更檢測時 被調用,并且函數參數也是在這時被傳入的。讓我們看看函數內部做了哪些工作。

    _ck 就是 check 的縮寫,其實就是函數 prodCheckAndUpdateNode,另一個參數就是 組件視圖數據。函數的主要功能就是從組件對象里拿到綁定屬性的當前值,然后和視圖數據對象、視圖節點索引等一起傳入 prodCheckAndUpdateNode 函數。其中,因為 Angular 會更新每一個視圖的 DOM,所以需要傳入當前視圖的索引。如果我們有兩個 span 和兩個組件:

    <b-comp [textContent]="AText"></b-comp>
    <b-comp [textContent]="AText"></b-comp>
    <span [textContent]="AText"></span>
    <span [textContent]="AText"></span>

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

    function(_ck, _v) {
     var _co = _v.component;
     var currVal_0 = _co.AText;
     
     // update first component
     _ck(_v, 1, 0, currVal_0);
     var currVal_1 = _co.AText;
     
     // update second component
     _ck(_v, 3, 0, currVal_1);
    }, 
    function(_ck, _v) {
     var _co = _v.component;
     var currVal_2 = _co.AText;
     
     // update first span
     _ck(_v, 4, 0, currVal_2);
     var currVal_3 = _co.AText;
    
     // update second span
     _ck(_v, 5, 0, currVal_3);
    }

    沒有什么更復雜的東西,這兩個函數還不是重點,重點是 _ck 函數,接著往下看。

    更新元素的屬性

    從上文我們知道,編譯器生成的 updateRenderer 函數會在每一次變更檢測被調用,用來更新 DOM 元素的屬性,并且其參數 _ck 就是函數 prodCheckAndUpdateNode。對于 DOM 元素的更新,該函數經過一系列的函數調用后,最終會調用函數 checkAndUpdateElementValue,這個函數會檢查綁定標志位是 [attr.name, class.name, style.some] 其中的哪一個,又或者是屬性綁定:

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

    上面代碼就是剛剛說的幾個綁定類型,當綁定標志位是 BindingFlags.TypeProperty,會調用函數 setElementProperty,該函數內部也是通過調用 DOM Renderer 的 setProperty 方法來更新 DOM。

    注:setElementProperty 函數里這行代碼 view.renderer.setProperty(renderNode,name, renderValue);,renderer 就是 Renderer2 interface,它僅僅是一個接口,在瀏覽器平臺下,它的實現就是 DefaultDomRenderer2。

    更新指令的屬性

    上文中已經描述了 updateRenderer 函數是用來更新元素的屬性,而 updateDirective 是用來更新子組件的輸入綁定屬性,并且變更檢測期間傳入的參數 _ck 就是函數 prodCheckAndUpdateNode。只是進過一系列函數調用后,最終調用的函數卻是checkAndUpdateDirectiveInline,這是因為這次節點的標志位是 NodeFlags.TypeDirective

    checkAndUpdateDirectiveInline 函數主要功能如下:

    1. 從當前視圖節點里獲取組件/指令對象

    2. 檢查組件/指令對象的綁定屬性值是否發生改變

    3. 如果屬性發生改變:

      a. 如果變更策略設置為 OnPush,設置視圖狀態為 checksEnabled

      b. 更新子組件的綁定屬性值

      c. 準備 SimpleChange 數據和更新視圖的 oldValues 屬性,新值替換舊值

      d. 調用生命周期鉤子 ngOnChanges

    4. 如果該視圖是首次執行變更檢測,則調用生命周期鉤子 ngOnInit

    5. 調用生命周期鉤子 ngDoCheck

    當然,只有在生命周期鉤子在組件內定義了才被調用,Angular 使用 NodeDef 節點標志位來判斷是否有生命周期鉤子,如果查看源碼你會發現類似如下代碼:

    if (... && (def.flags & NodeFlags.OnInit)) {
     directive.ngOnInit();
    }
    if (def.flags & NodeFlags.DoCheck) {
     directive.ngDoCheck();
    }

    和更新元素節點一樣,更新指令時也同樣把上一次的值存儲在視圖數據的屬性 oldValues 里(注:即上面的 3.c 步驟)。

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

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

    文檔

    [譯]Angular屬性綁定更新機制-Laravel/Angular技術分享

    [譯]Angular屬性綁定更新機制-Laravel/Angular技術分享:本篇文章主要的講述了關于angularjs屬性綁定更新機制,還有angularjs更新屬性的詳解,都在這篇文章中,現在就讓我們一起來看這篇文章吧angularjs屬性綁定更新機制解釋:所有現代前端框架都是用組件來合成 UI,這樣很自然就會產生父子組件層級,這就需要框架提
    推薦度:
    標簽: 綁定 更新 技術
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 免费一级特黄a | 亚洲欧美日韩在线播放 | 国产a久久精品一区二区三区 | 欧美日韩视频一区二区三区 | 欧美日韩国产码高清综合人成 | 日韩欧美一二区 | 国产成人h片视频在线观看 国产超级乱淫片中文 | 亚洲精品不卡久久久久久 | 亚洲精品电影 | 国产精品视频免费看 | 精品在线观看免费 | 久久99精品国产99久久 | 欧美成人视屏 | 一级全黄毛片 | 一级特黄女毛毛片 | 亚洲视频在线播放 | 国产精品久久久久免费 | 久久久久国产精品美女毛片 | 国产成人黄网址在线视频 | 国产成人精品日本亚洲语音1 | 国产成人久久综合二区 | 亚洲色图欧美色 | 在线视频日韩 | 欧美一区二区在线观看 | 国内精品一区二区 | 日韩第七页 | 在线免费黄色 | 日韩毛片免费观看 | 欧美国产高清欧美 | 亚洲 欧美 日韩在线 | 久久99一区| 自拍偷拍亚洲视频 | 欧美伊香蕉久久综合类网站 | 国产精品一区二区四区 | 国产在线视频不卡 | 免费看男女做好爽好硬视频 | 日韩视频在线免费观看 | 国产精品视频播放 | 萌白酱喷水 | 91久久精品| 亚洲一区二区三区在线免费观看 |