Angular中如何对子组件列表实现内容投影?及带包装器的已知类型子组件批量渲染方案问询
实现自定义容器组件:循环包装子组件与渲染模板列表
当然可以实现!不过直接用<ng-content>没法逐个处理子组件,因为它是一次性投影所有内容。我们需要借助Angular的ContentChildren来获取投影进来的子组件或模板,再逐个渲染并包裹到你的包装器里。下面分两种场景给你详细方案:
一、处理已知类型的子组件(比如<app-custom-child>)
1. 先调整子组件,暴露内容模板
首先修改你的AppCustomChildComponent,把内部内容放到一个<ng-template>中,方便容器组件复用:
import { Component, Input, TemplateRef, ViewChild } from '@angular/core'; @Component({ selector: 'app-custom-child', template: ` <ng-template #content> <!-- 保留原来的子组件内容投影 --> <ng-content></ng-content> </ng-template> ` }) export class AppCustomChildComponent { @Input() name!: string; // 获取内容模板的引用 @ViewChild('content') contentTemplate!: TemplateRef<any>; }
2. 容器组件获取子组件并循环渲染
在AppCustomContainerComponent中,用@ContentChildren获取所有投影进来的子组件实例,然后遍历它们,把每个子组件的内容放到包装器里:
import { Component, ContentChildren, QueryList } from '@angular/core'; import { AppCustomChildComponent } from './app-custom-child.component'; @Component({ selector: 'app-custom-container', template: ` <div class="container"> <ng-container *ngFor="let child of children"> <app-custom-child-internal-wrapper [id]="child.name"> <!-- 渲染当前子组件的内容模板 --> <ng-template [ngTemplateOutlet]="child.contentTemplate"></ng-template> </app-custom-child-internal-wrapper> </ng-container> </div> ` }) export class AppCustomContainerComponent { // 获取所有投影的子组件实例 @ContentChildren(AppCustomChildComponent) children!: QueryList<AppCustomChildComponent>; }
这样就能完美复用原来子组件的内容,同时每个子组件都被包裹在你的自定义包装器里,还能传递id属性。
二、渲染<ng-template>列表
如果需要传递并渲染多个<ng-template>,方法类似,只是我们直接获取TemplateRef实例即可:
容器组件代码
import { Component, ContentChildren, QueryList, TemplateRef } from '@angular/core'; @Component({ selector: 'app-custom-container', template: ` <div class="container"> <ng-container *ngFor="let template of templates; let i = index"> <app-custom-child-internal-wrapper [id]="'template-' + i"> <ng-template [ngTemplateOutlet]="template"></ng-template> </app-custom-child-internal-wrapper> </ng-container> </div> ` }) export class AppCustomContainerComponent { // 获取所有投影进来的ng-template @ContentChildren(TemplateRef) templates!: QueryList<TemplateRef<any>>; }
使用方式
<app-custom-container> <ng-template>模板内容1</ng-template> <ng-template>模板内容2</ng-template> <ng-template>模板内容3</ng-template> </app-custom-container>
额外提示:同时支持子组件和模板
如果想让容器同时兼容两种类型的内容,可以分别获取子组件和模板,合并后统一渲染:
@Component({ selector: 'app-custom-container', template: ` <div class="container"> <ng-container *ngFor="let item of combinedItems; let i = index"> <app-custom-child-internal-wrapper [id]="item.id || 'item-' + i"> <ng-template [ngTemplateOutlet]="item.template"></ng-template> </app-custom-child-internal-wrapper> </ng-container> </div> ` }) export class AppCustomContainerComponent { @ContentChildren(AppCustomChildComponent) childComponents!: QueryList<AppCustomChildComponent>; @ContentChildren(TemplateRef) templateRefs!: QueryList<TemplateRef<any>>; get combinedItems() { // 转换子组件为统一格式的对象 const children = this.childComponents.map(child => ({ id: child.name, template: child.contentTemplate })); // 转换模板为统一格式的对象 const templates = this.templateRefs.map((template, index) => ({ id: `template-${index}`, template })); // 合并后返回 return [...children, ...templates]; } }
这样你的容器就可以同时接收子组件和模板啦!
内容的提问来源于stack exchange,提问作者Ivan Koshelev
相关产品推荐
相关产品推荐

