Angular 4.x NgIf
NgIf 指令作用
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; } } 基础知识TemplateRefTemplateRef 实例用于表示模板对象,TemplateRef 抽象类的定义如下: // angularpackagescoresrclinkertemplate_ref.ts export abstract class TemplateRef<C> { abstract get elementRef(): ElementRef; abstract createEmbeddedView(context: C): EmbeddedViewRef<C>; } ViewContainerRefViewContainerRef 实例提供了 NgIfContextNgIfContext 实例用于表示 NgIf 上下文。 // angularpackagescommonsrcdirectivesng_if.ts export 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); } } } }
ViewContainerRef - createEmbeddedView()方法签名// angularpackagescoresrclinkerview_container_ref.ts export abstract class ViewContainerRef { /** * 基于TemplateRef对象创建Embedded View(内嵌视图),然后根据`index`指定的值,插入到容器中。 * 如果没有指定`index`的值,新创建的视图将作为容器中的最后一个视图插入。 */ abstract createEmbeddedView<C>( templateRef: TemplateRef<C>,context?: C,index?: number): EmbeddedViewRef<C>; } 方法实现// angularpackagescoresrcviewrefs.ts class ViewContainerRef_ implements ViewContainerData { // ... createEmbeddedView<C>( templateRef: TemplateRef<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; } 通过观察 TemplateRef - createEmbeddedView()方法签名// angularpackagescoresrclinkertemplate_ref.ts export abstract class TemplateRef<C> { abstract createEmbeddedView(context: C): EmbeddedViewRef<C>; } 方法实现// angularpackagescoresrcviewrefs.ts class 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 对象定义// angularpackagescoresrcviewtypes.ts export 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.ts export 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; } 在 function createProdServices() { return { setCurrentNode: () => {},createRootView: createProdRootView,createEmbeddedView: createEmbeddedView // 省略了其它方法 } createEmbeddedView() 方法// angularpackagescoresrcviewview.ts export 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; } 此时发现如果完整分析所有的方法,会涉及太多的内容。源码分析就到此结束,有兴趣的读者请自行阅读源码哈(请各位读者见谅)。接下来我们来总结一下 ViewContainerRef_ -> createEmbeddedView() => TemplateRef_ -> createEmbeddedView() => Services -> createEmbeddedView() => Call createEmbeddedView() (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- WebService CXF学习(入门篇4):整合Spring框架
- 为什么替换对象不会触发Angular2中的变化检测?
- Startup- and Shutdown sequence of OpenOffice.org
- Angular 4 依赖注入教程之七 ValueProvider的使用
- 用shell格式化输出json内容
- angularjs – Mocking $httpBackend – 如何处理“意外请求
- Bootstrap JS插件使用实例(1)-轮播
- bootstrap: 缩略图组件
- 如何对Scala和Play Framework中的SHA-1哈希进行base64编码?
- angularjs – 使用$rootscope显示和隐藏