Angular 2+:父组件中如何先展示所有grandchild-1再展示grandchild-2
解决Angular中跨层级组件内容收集与展示的问题
我懂你现在的需求:父组件里嵌套了多个子组件,每个子组件又包含grandchild-1和grandchild-2,想要先把所有grandchild-1做成带点击事件的列表,再统一展示所有grandchild-2的内容。之前用ng-content搞定了grandchild-2,但grandchild-1的列表一直没做出来,对吧?
咱们可以通过组件实例收集+模板引用的方式来解决,具体步骤如下:
1. 改造Grandchild组件,暴露内容模板
首先给grandchild-1和grandchild-2添加内部模板引用,方便父组件获取它们的内容:
grandchild-1.component.ts
import { Component, ViewChild, TemplateRef } from '@angular/core'; @Component({ selector: 'app-grandchild-1', template: ` <ng-template #content> <ng-content></ng-content> </ng-template> ` }) export class Grandchild1Component { @ViewChild('content') contentTemplate!: TemplateRef<any>; }
grandchild-2.component.ts
用同样的方式处理grandchild-2:
import { Component, ViewChild, TemplateRef } from '@angular/core'; @Component({ selector: 'app-grandchild-2', template: ` <ng-template #content> <ng-content></ng-content> </ng-template> ` }) export class Grandchild2Component { @ViewChild('content') contentTemplate!: TemplateRef<any>; }
2. 在子组件中持有Grandchild实例
修改ChildComponent,通过@ContentChild获取自己内部的两个grandchild组件实例:
child.component.ts
import { Component, ContentChild } from '@angular/core'; import { Grandchild1Component } from '../grandchild-1/grandchild-1.component'; import { Grandchild2Component } from '../grandchild-2/grandchild-2.component'; @Component({ selector: 'app-child', template: `` }) export class ChildComponent { @ContentChild(Grandchild1Component) grandchild1!: Grandchild1Component; @ContentChild(Grandchild2Component) grandchild2!: Grandchild2Component; }
3. 父组件收集所有Grandchild实例并渲染
在父组件中,通过@ContentChildren获取所有子组件,提取出所有grandchild-1和grandchild-2,最后在模板中渲染:
parent.component.ts
import { Component, ContentChildren, QueryList } from '@angular/core'; import { ChildComponent } from './child/child.component'; import { Grandchild1Component } from './grandchild-1/grandchild-1.component'; @Component({ selector: 'app-parent', template: ` <h3>Grandchild 1 列表</h3> <ul> <li *ngFor="let gc1 of allGrandchild1" (click)="parentMethod(gc1)"> <ng-container [ngTemplateOutlet]="gc1.contentTemplate"></ng-container> </li> </ul> <h3>Grandchild 2 内容</h3> <div *ngFor="let gc2 of allGrandchild2" class="gc2-container"> <ng-container [ngTemplateOutlet]="gc2.contentTemplate"></ng-container> </div> `, styles: [` ul { list-style: none; padding: 0; } li { padding: 8px; border: 1px solid #eee; margin: 4px 0; cursor: pointer; } .gc2-container { margin: 12px 0; padding: 12px; background: #f5f5f5; } `] }) export class ParentComponent { @ContentChildren(ChildComponent) childComponents!: QueryList<ChildComponent>; // 提取所有grandchild-1实例 get allGrandchild1(): Grandchild1Component[] { return this.childComponents.map(child => child.grandchild1); } // 提取所有grandchild-2实例 get allGrandchild2() { return this.childComponents.map(child => child.grandchild2); } parentMethod(gc1: Grandchild1Component) { console.log('点击了Grandchild 1:', gc1); // 这里可以添加你的业务逻辑 } }
4. 父组件的使用方式
最后在父组件的使用代码中,保持原来的嵌套结构即可:
<app-parent> <app-child> <app-grandchild-1>第一个子组件的Grandchild 1</app-grandchild-1> <app-grandchild-2>第一个子组件的Grandchild 2内容</app-grandchild-2> </app-child> <app-child> <app-grandchild-1>第二个子组件的Grandchild 1</app-grandchild-1> <app-grandchild-2>第二个子组件的Grandchild 2内容</app-grandchild-2> </app-child> </app-parent>
这样就能实现你要的效果:先展示所有grandchild-1的可点击列表,再依次展示所有grandchild-2的内容。核心思路是通过@ContentChild/@ContentChildren跨层级获取组件实例,再利用ngTemplateOutlet渲染组件内部的内容模板。
内容的提问来源于stack exchange,提问作者monty
相关产品推荐
相关产品推荐

