Content顾名思义是内容,它与放置在<ng-content></ng-content>
里面的投影内容息息相关。
1. 回顾一下ng-content
greet.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'exe-greet',
template: `
<div class="border">
<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 Minghao</p> // 在exe-greet标签中放置的内容将会投影到ng-content处
</exe-greet>
`,
})
export class AppComponent { }
此时网页上输出的内容,假设我们将 my-app 的template内容显示出来
<h4>Welcome to Angular World</h4>
<div class="border">
<p>Hello Minghao</p> // exe-greet的内容如左边所示
</div>
2. ng-content支持select属性
有人可能会说上面那样太简单了,实际需求中可能会稍微复杂一些,要插入的内容需要自定义,甚至是放入某些节点里面包裹起来,而且可能有不同的组件需要用到greet这个组件,行,那我们来改进一下。
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 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>
</div>
`,
styles: [` .border { border: 2px solid #eee; } `]
})
export class GreetComponent{ }
GreetComponent 组件已经调整好了,现在剩下的问题就是如何从父级组件动态的抽取各个部分的内容。幸运的是,ng-content
指令支持 select
属性,它允许我们设定抽取的内容,更强大的是它支持我们常用的选择器类型,如标签选择器、类选择器、ID选择器、属性选择器
等。
下面来改善一下父模板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 { }
此时网页上输出的内容,假设我们将 my-app 的template内容显示出来
<h4>Welcome to Angular World</h4>
<div class="border">
<p>Greet Component</p>
<div style="border: 1px solid #666;margin: 4px;">
<div style="border: 1px solid red;margin: 5px;">
<header>Card Header</header> // 标签选择器
</div>
<div style="border: 1px solid green;margin: 5px;">
<div class="card_body">Card Body</div> // 类选择器
</div>
<div style="border: 1px solid blue;margin: 5px;">
<footer>Card Footer</footer> // 标签选择器
</div>
</div>
</div>
3. 切入正题,谈谈@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 { }
以上代码运行后,控制台的输出结果:
ContentChild.png
ContentChildren
ContentChildren 属性装饰器用来从通过 Content Projection 方式设置的视图中获取匹配的多个元素,返回的结果是一个 QueryList 集合。
parent.component.ts
import { Component, ContentChildren, QueryList, 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 {
@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 { }
以上代码运行后,控制台的输出结果:
ContentChild2.png
Something else
-
ContentChildren 与 ViewChildren 的定义
-
在 host 元素 <opening> 和 </closing> 标签中被称为 Content Children
-
在组件的模板中定义的内容,它是组件的一部分,被称为 View Children
-
-
ContentChild 与 ViewChild 的异同点
-
相同点
1.都是属性装饰器
2.都有对应的复数形式装饰器:ContentChildren、ViewChildren
3.都支持 Type<any>|Function|string 类型的选择器
-
不同点
1.ContentChild 用来从通过 Content Projection 方式 (ng-content) 设置的视图中获取匹配的元素
2.ViewChild 用来从模板视图中获取匹配的元素
3.在父组件的 ngAfterContentInit 生命周期钩子中才能成功获取通过 ContentChild 查询的元素
4.在父组件的 ngAfterViewInit 生命周期钩子中才能成功获取通过 ViewChild 查询的元素
(reference by semlinker)
网友评论