如何在Angular子组件的多个位置渲染同一份ng-content内容
问题根因
你遇到的问题本质是Angular中<ng-content>的单次投射特性:<ng-content>只会将传入的DOM节点移动到它第一次被渲染的位置,你将<ng-content>包裹在单个<ng-template>中多次调用*ngTemplateOutlet时,并不会生成新的DOM副本,只会将同一组DOM节点在不同渲染位置之间移动。当你打开mat-menu时,菜单内的模板被激活渲染,按钮节点就被移动到了菜单中,原组件区域的按钮自然就消失了。
修复方案
调整为「父组件传入模板引用、容器组件多次渲染模板」的方式即可实现多位置渲染,每次调用模板都会生成独立的DOM节点,不会出现节点被移动的问题:
1. 修改容器组件逻辑
首先在容器组件的ts文件中添加@ContentChild注解,接收父组件传入的模板:
import { Component, ContentChild, TemplateRef } from '@angular/core'; @Component({ selector: 'container', templateUrl: './container.component.html', styleUrls: ['./container.component.css'] }) export class ContainerComponent { // 接收父组件传入的contentTpl模板 @ContentChild('contentTpl') contentTpl!: TemplateRef<any>; }
容器组件的模板保持原有渲染逻辑即可,无需修改:
<section id="buttons"> <ng-container *ngTemplateOutlet="contentTpl"></ng-container> </section> <button mat-button [matMenuTriggerFor]="menu">Menu</button> <mat-menu #menu="matMenu"> <ng-container *ngTemplateOutlet="contentTpl"></ng-container> </mat-menu>
2. 调整父组件调用方式
将需要重复渲染的按钮内容包裹在ng-template标签中,标注模板引用#contentTpl即可:
<container> <ng-template #contentTpl> <button mat-raised-button (click)="foo()">foo</button> <button mat-raised-button (click)="bar()">bar</button> </ng-template> </container>
该方案下两个位置渲染的按钮是完全独立的DOM节点,点击事件和样式都不会互相影响,打开菜单时原位置的按钮也不会消失。
内容的提问来源于stack exchange,提问作者Jon Sud
相关产品推荐
相关产品推荐

