Angular 中 ContentChild & ContentChildren

Content顾名思义是内容,它与放置在里面的投影内容息息相关。


1. 回顾一下ng-content

greet.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'exe-greet',
    template: `
    
// 投影处
`, styles: [` .border { border: 2px solid #eee; } `] }) export class GreetComponent { }

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    

Welcome to Angular World

Hello Minghao

// 在exe-greet标签中放置的内容将会投影到ng-content处
`, }) export class AppComponent { }

此时网页上输出的内容,假设我们将 my-app 的template内容显示出来

    

Welcome to Angular World

Hello Minghao

// exe-greet的内容如左边所示

2. ng-content支持select属性

有人可能会说上面那样太简单了,实际需求中可能会稍微复杂一些,要插入的内容需要自定义,甚至是放入某些节点里面包裹起来,而且可能有不同的组件需要用到greet这个组件,行,那我们来改进一下。

import { Component } from '@angular/core';

@Component({
    selector: 'exe-greet',
    template: `
    

Greet Component

// 标签选择器
// 类选择器
// 标签选择器
`, 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: `
    

Welcome to Angular World

Card Header
Card Body
Card Footer
`, }) export class AppComponent { }

此时网页上输出的内容,假设我们将 my-app 的template内容显示出来

    

Welcome to Angular World

Greet Component

Card Header
// 标签选择器
Card Body
// 类选择器
Card Footer
// 标签选择器

3. 切入正题,谈谈@ContentChild

child.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'exe-child',
    template: `
      

Child Component

` }) 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: `
      

Parent Component

` }) 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: `
    

Welcome to Angular World

`, }) export class AppComponent { }

以上代码运行后,控制台的输出结果:


Angular 中 ContentChild & ContentChildren_第1张图片
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: `
      

Parent Component

` }) export class ParentComponent implements AfterContentInit { @ContentChildren(ChildComponent) childCmps: QueryList; ngAfterContentInit() { console.dir(this.childCmps); } }

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    

Welcome to Angular World

`, }) export class AppComponent { }

以上代码运行后,控制台的输出结果:


Angular 中 ContentChild & ContentChildren_第2张图片
ContentChild2.png

Something else

  • ContentChildren 与 ViewChildren 的定义
    • 在 host 元素 和 标签中被称为 Content Children

    • 在组件的模板中定义的内容,它是组件的一部分,被称为 View Children

  • ContentChild 与 ViewChild 的异同点
  • 相同点

1.都是属性装饰器

2.都有对应的复数形式装饰器:ContentChildren、ViewChildren

3.都支持 Type|Function|string 类型的选择器

  • 不同点

1.ContentChild 用来从通过 Content Projection 方式 (ng-content) 设置的视图中获取匹配的元素

2.ViewChild 用来从模板视图中获取匹配的元素

3.在父组件的 ngAfterContentInit 生命周期钩子中才能成功获取通过 ContentChild 查询的元素

4.在父组件的 ngAfterViewInit 生命周期钩子中才能成功获取通过 ViewChild 查询的元素

(reference by semlinker)

你可能感兴趣的:(Angular 中 ContentChild & ContentChildren)