Angular中ForOf循环内重复ng-content仅渲染一次的问题
<ng-content>只渲染一次? 你碰到的这个问题其实是Angular内容投射(Content Projection)的内置行为导致的——<ng-content>的本质是「移动」外部传入的DOM内容,而不是「复制」它,所以不管你循环多少次,最终只会看到一份投射内容。
具体原因
Angular的<ng-content>是基于DOM节点的「移动机制」工作的:你在父组件里写的<input>是一个真实的DOM节点,而一个DOM节点不能同时存在于DOM树的多个位置。当你的*ngFor循环执行时,每一次迭代都会尝试把这个<input>节点移动到当前的<div>容器里,等循环结束,这个节点就停在了最后一次循环的<div>中,所以你最终只看到1个按钮。
解决方案:用模板+*ngTemplateOutlet实现重复渲染
要实现循环内重复渲染外部内容,我们需要用<ng-template>把外部内容封装成可复用的模板,然后在子组件中通过*ngTemplateOutlet多次实例化这个模板——因为模板可以被多次渲染,每次都会生成新的DOM节点/组件实例。
基础实现步骤:
父组件:用
<ng-template>封装内容
把需要重复的内容放到<ng-template>里,并给它一个模板引用变量(比如#contentTemplate):@Component({ selector: 'app-card-with-options', template: ` <app-card> <ng-template #contentTemplate> <input type="submit" value="提交"> </ng-template> </app-card> ` }) export class AppCardWithOptionsComponent {}子组件:获取模板并循环渲染
通过@ContentChild获取父组件传递的模板,然后在循环中用*ngTemplateOutlet渲染模板:import { Component, ContentChild, TemplateRef } from '@angular/core'; @Component({ selector: 'app-card', template: ` <div *ngFor="let x of [1,2,3,4,5,6]"> {{x}} <ng-container *ngTemplateOutlet="contentTemplate"></ng-container> </div> ` }) export class AppCardComponent { @ContentChild('contentTemplate') contentTemplate!: TemplateRef<any>; }
进阶:给模板传递上下文数据
如果需要给每个循环的内容传递当前循环的变量(比如x的值),可以通过*ngTemplateOutlet的context参数传递:
- 子组件模板修改:
<div *ngFor="let x of [1,2,3,4,5,6]"> {{x}} <ng-container *ngTemplateOutlet="contentTemplate; context: { $implicit: x }"></ng-container> </div> - 父组件模板接收上下文:
<ng-template #contentTemplate let-number> <input type="submit" value="提交 {{number}}"> </ng-template>
总结
<ng-content>适合单次内容投射的场景,当你需要重复渲染外部传入的内容时,一定要用「模板引用 + *ngTemplateOutlet」的组合——它能帮你创建多份独立的内容实例,完美解决循环内重复渲染的需求。
内容的提问来源于stack exchange,提问作者sadaf2605

