的用法_AngularJS_脚本之家

NgIf 指令作用

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

then 模板除非绑定到不同的值,否则默认是 ngIf 指令关联的内联模板。 else
模板除非绑定对应的值,否则默认是 null。

NgIf 指令语法

......

......

使用then和else块

......

{{value}}...

NgIf 使用示例

@Component({ selector: 'ng-if-then-else', template: ` {{show ? 'hide' : 'show'}} Switch Primary show = {{show}} 
 this is ignored Primary text to show Secondary text to show Alternate text while primary text is hidden `})class NgIfThenElse implements OnInit { thenBlock: TemplateRef = null; show: boolean = true; @ViewChild primaryBlock: TemplateRef = null; @ViewChild secondaryBlock: TemplateRef = null; switchPrimary() { this.thenBlock = this.thenBlock === this.primaryBlock ? this.secondaryBlock : this.primaryBlock; } ngOnInit() { this.thenBlock = this.primaryBlock; }}

基础知识

TemplateRefTemplateRef 实例用于表示模板对象,TemplateRef
抽象类的定义如下:

// angularpackagescoresrclinkertemplate_ref.tsexport abstract class TemplateRef { abstract get elementRef(): ElementRef; abstract createEmbeddedView: EmbeddedViewRef;}

ViewContainerRef

ViewContainerRef 实例提供了createEmbeddedView()方法,该方法接收
TemplateRef对象作为参数,并将模板中的内容作为容器
的兄弟元素,插入到页面中。

NgIfContext

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

// angularpackagescommonsrcdirectivesng_if.tsexport class NgIfContext { public $implicit: any = null; public ngIf: any = null;}

NgIf 源码分析

NgIf 指令定义

@Directive({ selector: '[ngIf]' // 属性选择器 - })

NgIf 类私有属性及构造函数

export class NgIf { // 创建NgIfContext上下文 private _context: NgIfContext = new NgIfContext(); // 表示then模板对象 private _thenTemplateRef: TemplateRef|null = null; // 表示else模板对象 private _elseTemplateRef: TemplateRef|null = null; // 表示根据then模板创建的EmbeddedViewRef视图 private _thenViewRef: EmbeddedViewRef|null = null; // 表示根据else模板创建的EmbeddedViewRef视图 private _elseViewRef: EmbeddedViewRef|null = null; constructor( private _viewContainer: ViewContainerRef, templateRef: TemplateRef) { this._thenTemplateRef = templateRef; // then模板的默认值为ngIf指令关联的内联模板 }}

NgIf 类输入属性

@Input()set ngIf { this._context.$implicit = this._context.ngIf = condition; this._updateViewset ngIfThen(templateRef: TemplateRef) { this._thenTemplateRef = templateRef; this._thenViewRef = null; // 清除之前创建的视图 this._updateViewset ngIfElse(templateRef: TemplateRef) { 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._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._viewContainer.clear(); this._thenViewRef = null; if (this._elseTemplateRef) { this._elseViewRef = this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context); } } }}

ngIf指令的源码相对比较简单,最核心的是
_updateView()方法。而该方法中最重要的功能就是如何基于模板对象创建内嵌视图。接下来我们来分析一下
ViewContainerRef对象的createEmbeddedView()方法。

ViewContainerRef – createEmbeddedView()

// angularpackagescoresrclinkerview_container_ref.tsexport abstract class ViewContainerRef { /** * 基于TemplateRef对象创建Embedded View,然后根据`index`指定的值,插入到容器中。 * 如果没有指定`index`的值,新创建的视图将作为容器中的最后一个视图插入。 */ abstract createEmbeddedView( templateRef: TemplateRef, context?: C, index?: number): EmbeddedViewRef;}

// angularpackagescoresrcviewrefs.tsclass ViewContainerRef_ implements ViewContainerData { // ... createEmbeddedView( templateRef: TemplateRef, context?: C, index?: number): EmbeddedViewRef { // 调用TemplateRef对象createEmbeddedView()方法创建EmbeddedViewRef对象 const viewRef = templateRef.createEmbeddedView; // 根据指定的index值,插入到视图容器中 this.insert; 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()

// angularpackagescoresrclinkertemplate_ref.tsexport abstract class TemplateRef { abstract createEmbeddedView: EmbeddedViewRef;}

// angularpackagescoresrcviewrefs.tsclass TemplateRef_ extends TemplateRef implements TemplateData { // ... createEmbeddedView: EmbeddedViewRef { return new ViewRef_(Services.createEmbeddedView( this._parentView, this._def, this._def.element !.template !, context)); }}export interface TemplateData extends TemplateRef { _projectedViews: ViewData[];}

看完上面的源码,毫无疑问接下来我们要继续分析
Services对象中的createEmbeddedView()方法。

Services – createEmbeddedView()

Services 对象定义

// angularpackagescoresrcviewtypes.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 对象初始化

// angularpackagescoresrcviewservices.tsexport function initServicesIfNeeded { 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() 方法

// angularpackagescoresrcviewview.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; return view;}

此时发现如果完整分析所有的方法,会涉及太多的内容。源码分析就到此结束,有兴趣的读者请自行阅读源码哈。接下来我们来总结一下createEmbeddedView()方法调用流程:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

发表评论

电子邮件地址不会被公开。 必填项已用*标注