Angular 2 ContentChild & ContentChildren
前面的文章我们已经介绍过了 Angular 2 的 ViewChild & ViewChildren 属性装饰器,现在我们就来介绍一下它们的兄弟 ContentChild 和 ContentChildren 属性装饰器。我想通过一个简单的需求,来引入我们今天的主题。具体需求如下:
熟悉 Angular 1.x 的用户,应该都知道 greet.component.ts import { Component } from '@angular/core'; @Component({ selector: 'exe-greet',template: ` <div class="border"> <p>Greet Component</p> <ng-content></ng-content> </div> `,styles: [` .border { border: 2px solid #eee; } `] }) export class GreetComponent { } app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'my-app',template: ` <h4>Welcome to Angular World</h4> <exe-greet> <p>Hello Semlinker</p> </exe-greet> `,}) export class AppComponent { } 以上代码运行后,浏览器的输出结果:
是不是感觉太简单了,那我们来升级一下需求,即我们的 GreetComponent 组件要支持用户自定义卡片风格的问候内容,具体如下图所示:
这个功能也很简单啊,我们马上看一下代码: import { Component } from '@angular/core'; @Component({ selector: 'my-app',template: ` <h4>Welcome to Angular World</h4> <exe-greet> <div style="border: 1px solid #666; margin: 4px;"> <div style="border: 1px solid red; margin: 5px;">Card Header</div> <div style="border: 1px solid green; margin: 5px;">Card Body</div> <div style="border: 1px solid blue; margin: 5px;">Card Footer</div> </div> </exe-greet> `,}) export class AppComponent { } 以上代码运行后,浏览器的输出结果:
功能是实现了,但有没有什么问题 ?假设在另一个页面,也需要使用 GreetComponent 组件 ,那么还需要再次设置预设的样式。我们能不能把卡片风格的各个部分默认样式定义在 GreetComponent 组件中,使用组件时我们只需关心自定内容区域的样式,答案是可以的,调整后的代码如下: import { Component } from '@angular/core'; @Component({ selector: 'exe-greet',template: ` <div class="border"> <p>Greet Component</p> <div style="border: 1px solid #666;margin: 4px;"> <div style="border: 1px solid red;margin: 5px;"> <ng-content></ng-content> </div> <div style="border: 1px solid green;margin: 5px;"> <ng-content></ng-content> </div> <div style="border: 1px solid blue;margin: 5px;"> <ng-content></ng-content> </div> </div> </div> `,styles: [` .border { border: 2px solid #eee; } `] }) export class GreetComponent{ } GreetComponent 组件已经调整好了,现在剩下的问题就是如何从父级组件动态的抽取各个部分的内容。幸运的是, greet.component.ts - template <div style="border: 1px solid #666;margin: 4px;"> <div style="border: 1px solid red;margin: 5px;"> <ng-content select="header"></ng-content> </div> <div style="border: 1px solid green;margin: 5px;"> <ng-content select=".card_body"></ng-content> </div> <div style="border: 1px solid blue;margin: 5px;"> <ng-content select="footer"></ng-content> </div> </div> app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'my-app',template: ` <h4>Welcome to Angular World</h4> <exe-greet> <header>Card Header</header> <div class="card_body">Card Body</div> <footer>Card Footer</footer> </exe-greet> `,}) export class AppComponent { } 以上代码运行后,在浏览上我们可以看到预期的结果,接下来该我们的主角 - ContentChild 出场了。 ContentChild在正式介绍 ContentChild 属性装饰器前,我们要先了解一下 Content Projection (内容投影)。
以前面的例子为例,我们在 ContentChild 是属性装饰器,用来从通过 Content Projection 方式设置的视图中获取匹配的元素。 @ContentChild 示例child.component.ts import { Component } from '@angular/core'; @Component({ selector: 'exe-child',template: ` <p>Child Component</p> ` }) export class ChildComponent { name: string = 'child-component'; } parent.component.ts import { Component,ContentChild,AfterContentInit } from '@angular/core'; import { ChildComponent } from './child.component'; @Component({ selector: 'exe-parent',template: ` <p>Parent Component</p> <ng-content></ng-content> ` }) export class ParentComponent implements AfterContentInit { @ContentChild(ChildComponent) childCmp: ChildComponent; ngAfterContentInit() { console.dir(this.childCmp); } } app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'my-app',template: ` <h4>Welcome to Angular World</h4> <exe-parent> <exe-child></exe-child> </exe-parent> `,}) export class AppComponent { } 以上代码运行后,控制台的输出结果:
ContentChildrenContentChildren 属性装饰器用来从通过 Content Projection 方式设置的视图中获取匹配的多个元素,返回的结果是一个 QueryList 集合。 @ContentChildren 示例 parent.component.ts import { Component,ContentChildren,QueryList,template: ` <p>Parent Component</p> <ng-content></ng-content> ` }) export class ParentComponent implements AfterContentInit { @ContentChildren(ChildComponent) childCmps: QueryList<ChildComponent>; ngAfterContentInit() { console.dir(this.childCmps); } } app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'my-app',template: ` <h4>Welcome to Angular World</h4> <exe-parent> <exe-child></exe-child> <exe-child></exe-child> </exe-parent> `,}) export class AppComponent { } 以上代码运行后,控制台的输出结果:
ContentChild 接口及装饰器ContentChildDecorator 接口export interface ContentChildDecorator { // Type类型:@ContentChild(ChildComponent) (selector: Type<any>|Function|string,{read}?: {read?: any}): any; new (selector: Type<any>|Function|string,{read}?: {read?: any}): ContentChild; } ContentChildDecorator 装饰器export const ContentChild: ContentChildDecorator = makePropDecorator( 'ContentChild',[ ['selector',undefined],{ first: true,isViewQuery: false,// ViewChild或ViewChildren装饰器时为true descendants: true,read: undefined,} ],Query); 我有话说ContentChildren 与 ViewChildren 的定义
ContentChild 与 ViewChild 的异同点相同点
不同点
在 Root Component 中无法使用 `ng-content
原因主要有以下几点:
总结本文先通过一个简单的需求,引出了 Angular 2 中的 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |