国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

詳解Angular 4.x NgIf 的用法

2019-11-19 16:31:55
字體:
來源:轉載
供稿:網友

NgIf 指令作用

ngIf 指令用于根據表達式的值,在指定位置渲染 then 或 else 模板的內容。

  1. then 模板除非綁定到不同的值,否則默認是 ngIf 指令關聯的內聯模板。
  2. else 模板除非綁定對應的值,否則默認是 null。

NgIf 指令語法

簡單形式

<!--語法糖--><div *ngIf="condition">...</div><!--Angular 2.x中使用template--><ng-template [ngIf]="condition"><div>...</div></ng-template>

使用else塊

<div *ngIf="condition; else elseBlock">...</div><ng-template #elseBlock>...</ng-template>

使用then和else塊

<div *ngIf="condition; then thenBlock else elseBlock"></div><ng-template #thenBlock>...</ng-template><ng-template #elseBlock>...</ng-template>

使用as語法

<div *ngIf="condition as value; else elseBlock">{{value}}</div><ng-template #elseBlock>...</ng-template>

NgIf 使用示例

@Component({ selector: 'ng-if-then-else', template: `  <button (click)="show = !show">{{show ? 'hide' : 'show'}}</button>  <button (click)="switchPrimary()">Switch Primary</button>    show = {{show}}  <br>  <div *ngIf="show; then thenBlock; else elseBlock">this is ignored</div>  <ng-template #primaryBlock>Primary text to show</ng-template>  <ng-template #secondaryBlock>Secondary text to show</ng-template>  <ng-template #elseBlock>Alternate text while primary text is hidden</ng-template> `})class NgIfThenElse implements OnInit { thenBlock: TemplateRef<any> = null; show: boolean = true;  @ViewChild('primaryBlock') primaryBlock: TemplateRef<any> = null; @ViewChild('secondaryBlock') secondaryBlock: TemplateRef<any> = null;  switchPrimary() {  this.thenBlock = this.thenBlock === this.primaryBlock ?    this.secondaryBlock : this.primaryBlock; }  ngOnInit() {    this.thenBlock = this.primaryBlock; }}

基礎知識

TemplateRef
TemplateRef 實例用于表示模板對象,TemplateRef 抽象類的定義如下:

// angular/packages/core/src/linker/template_ref.tsexport abstract class TemplateRef<C> { abstract get elementRef(): ElementRef; abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;}

ViewContainerRef

ViewContainerRef 實例提供了 createEmbeddedView() 方法,該方法接收 TemplateRef 對象作為參數,并將模板中的內容作為容器 (comment 元素) 的兄弟元素,插入到頁面中。

NgIfContext

NgIfContext 實例用于表示 NgIf 上下文。

// angular/packages/common/src/directives/ng_if.tsexport class NgIfContext { public $implicit: any = null; public ngIf: any = null;}

NgIf 源碼分析

NgIf 指令定義

@Directive({  selector: '[ngIf]' // 屬性選擇器 - <ng-template [ngIf]="condition">})

NgIf 類私有屬性及構造函數

export class NgIf { // 創建NgIfContext上下文 private _context: NgIfContext = new NgIfContext(); // 表示then模板對象 private _thenTemplateRef: TemplateRef<NgIfContext>|null = null; // 表示else模板對象 private _elseTemplateRef: TemplateRef<NgIfContext>|null = null; // 表示根據then模板創建的EmbeddedViewRef視圖 private _thenViewRef: EmbeddedViewRef<NgIfContext>|null = null; // 表示根據else模板創建的EmbeddedViewRef視圖 private _elseViewRef: EmbeddedViewRef<NgIfContext>|null = null; constructor(  private _viewContainer: ViewContainerRef,   templateRef: TemplateRef<NgIfContext>) {   this._thenTemplateRef = templateRef; // then模板的默認值為ngIf指令關聯的內聯模板 }}

NgIf 類輸入屬性

@Input()set ngIf(condition: any) {  this._context.$implicit = this._context.ngIf = condition;  this._updateView(); // 更新視圖}@Input()set ngIfThen(templateRef: TemplateRef<NgIfContext>) {  this._thenTemplateRef = templateRef;  this._thenViewRef = null; // 清除之前創建的視圖  this._updateView();}@Input()set ngIfElse(templateRef: TemplateRef<NgIfContext>) {  this._elseTemplateRef = templateRef;  this._elseViewRef = null; // 清除之前創建的視圖  this._updateView();}

_updateView() 私有方法

// 更新視圖private _updateView() { // this._context.$implicit = this._context.ngIf = condition // 若condition表達式的值為truthy if (this._context.$implicit) { // 若_thenViewRef為null且_thenTemplateRef存在,則創建_thenViewRef內嵌視圖   if (!this._thenViewRef) {    this._viewContainer.clear();    this._elseViewRef = null;    if (this._thenTemplateRef) {     this._thenViewRef =       this._viewContainer.createEmbeddedView(this._thenTemplateRef,        this._context);    }   }  } else { // condition表達式的值為falsy   // 若_elseViewRef為null且_elseTemplateRef存在,則創建_elseViewRef內嵌視圖   if (!this._elseViewRef) {    this._viewContainer.clear();    this._thenViewRef = null;    if (this._elseTemplateRef) {     this._elseViewRef =       this._viewContainer.createEmbeddedView(this._elseTemplateRef,         this._context);    }   }  }}

ngIf 指令的源碼相對比較簡單,最核心的是 _updateView() 方法。而該方法中最重要的功能就是如何基于模板對象創建內嵌視圖。接下來我們來分析一下 ViewContainerRef 對象的 createEmbeddedView() 方法。

ViewContainerRef - createEmbeddedView()

方法簽名

// angular/packages/core/src/linker/view_container_ref.tsexport abstract class ViewContainerRef {  /**  * 基于TemplateRef對象創建Embedded View(內嵌視圖),然后根據`index`指定的值,插入到容器中。   * 如果沒有指定`index`的值,新創建的視圖將作為容器中的最后一個視圖插入。  */  abstract createEmbeddedView<C>(   templateRef: TemplateRef<C>,    context?: C, index?: number):   EmbeddedViewRef<C>;}

方法實現

// angular/packages/core/src/view/refs.tsclass ViewContainerRef_ implements ViewContainerData {  // ...  createEmbeddedView<C>(   templateRef: TemplateRef<C>,    context?: C, index?: number):   EmbeddedViewRef<C> {    // 調用TemplateRef對象createEmbeddedView()方法創建EmbeddedViewRef對象    const viewRef = templateRef.createEmbeddedView(context || <any>{});     // 根據指定的index值,插入到視圖容器中    this.insert(viewRef, index);    return viewRef; }}// ViewContainerData接口繼承于ViewContainerRef抽象類export interface ViewContainerData extends ViewContainerRef { _embeddedViews: ViewData[];}export interface ViewData { def: ViewDefinition; root: RootData; renderer: Renderer2; parentNodeDef: NodeDef|null; parent: ViewData|null; viewContainerParent: ViewData|null; component: any; context: any; nodes: {[key: number]: NodeData}; state: ViewState; oldValues: any[]; disposables: DisposableFn[]|null;}

通過觀察 ViewContainerRef_ 類中的 createEmbeddedView() 方法,我們發現該方法內部是調用 TemplateRef 對象的 createEmbeddedView() 方法來創建內嵌視圖。因此接下來我們再來分析一下 TemplateRef 對象的 createEmbeddedView() 方法。

TemplateRef - createEmbeddedView()

方法簽名

// angular/packages/core/src/linker/template_ref.tsexport abstract class TemplateRef<C> { abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;}

方法實現

// angular/packages/core/src/view/refs.tsclass TemplateRef_ extends TemplateRef<any> implements TemplateData { // ... createEmbeddedView(context: any): EmbeddedViewRef<any> {  return new ViewRef_(Services.createEmbeddedView(    this._parentView, this._def, this._def.element !.template !, context)); }}export interface TemplateData extends TemplateRef<any> { _projectedViews: ViewData[];}

看完上面的源碼,毫無疑問接下來我們要繼續分析 Services 對象中的 createEmbeddedView() 方法。

Services - createEmbeddedView()

Services 對象定義

// angular/packages/core/src/view/types.tsexport const Services: Services = { setCurrentNode: undefined !, createRootView: undefined !, createEmbeddedView: undefined !, createComponentView: undefined !, createNgModuleRef: undefined !, overrideProvider: undefined !, clearProviderOverrides: undefined !, checkAndUpdateView: undefined !, checkNoChangesView: undefined !, destroyView: undefined !, resolveDep: undefined !, createDebugContext: undefined !, handleEvent: undefined !, updateDirectives: undefined !, updateRenderer: undefined !, dirtyParentQueries: undefined !,};

Services 對象初始化

// angular/packages/core/src/view/services.tsexport function initServicesIfNeeded() { if (initialized) {  return; } initialized = true; const services = isDevMode() ? createDebugServices() : createProdServices(); Services.setCurrentNode = services.setCurrentNode; Services.createRootView = services.createRootView; Services.createEmbeddedView = services.createEmbeddedView; Services.createComponentView = services.createComponentView; Services.createNgModuleRef = services.createNgModuleRef; Services.overrideProvider = services.overrideProvider; Services.clearProviderOverrides = services.clearProviderOverrides; Services.checkAndUpdateView = services.checkAndUpdateView; Services.checkNoChangesView = services.checkNoChangesView; Services.destroyView = services.destroyView; Services.resolveDep = resolveDep; Services.createDebugContext = services.createDebugContext; Services.handleEvent = services.handleEvent; Services.updateDirectives = services.updateDirectives; Services.updateRenderer = services.updateRenderer; Services.dirtyParentQueries = dirtyParentQueries;}

initServicesIfNeeded() 方法中,會根據當前所處的模式,創建不同的 Services 對象。接下來 我們直接來看一下 createProdServices() 方法:

function createProdServices() { return {  setCurrentNode: () => {},  createRootView: createProdRootView,  createEmbeddedView: createEmbeddedView // 省略了其它方法}

createEmbeddedView() 方法

// angular/packages/core/src/view/view.tsexport function createEmbeddedView(  parent: ViewData, anchorDef: NodeDef, viewDef: ViewDefinition, context?: any): ViewData { // embedded views are seen as siblings to the anchor, so we need // to get the parent of the anchor and use it as parentIndex. // 創建ViewData對象 const view = createView(parent.root, parent.renderer, parent, anchorDef, viewDef); // 初始化ViewData對象-設置component及context屬性的值 initView(view, parent.component, context); // 創建視圖中的節點,即設置view.nodes數組的屬性值 // const nodes = view.nodes; for(...) { ...; nodes[i] = nodeData; } createViewNodes(view); return view;}

此時發現如果完整分析所有的方法,會涉及太多的內容。源碼分析就到此結束,有興趣的讀者請自行閱讀源碼哈(請各位讀者見諒)。接下來我們來總結一下 createEmbeddedView() 方法調用流程:

ViewContainerRef_ -> createEmbeddedView()  => TemplateRef_ -> createEmbeddedView()  => Services -> createEmbeddedView()   => Call createEmbeddedView()

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 吕梁市| 建瓯市| 铅山县| 弥勒县| 巩义市| 杨浦区| 甘肃省| 鄂温| 巨野县| 建水县| 岑巩县| 彩票| 革吉县| 浮山县| 米林县| 漠河县| 赤城县| 鹤峰县| 若羌县| 佛冈县| 镇赉县| 荔浦县| 苏尼特左旗| 玉溪市| 来凤县| 清丰县| 措美县| 涿鹿县| 察哈| 康马县| 高州市| 富顺县| 滦南县| 吉木萨尔县| 库尔勒市| 环江| 兴安盟| 方正县| 蓬莱市| 内江市| 临武县|