如何通过函数确定*ngTemplateOutlet要渲染的目标模板?
问题根因
*ngTemplateOutlet 仅支持接收 TemplateRef 类型的实例作为输入值,你之前返回模板引用的字符串名称(比如tab1/tab2),Angular无法识别到对应的模板实例,所以不会生效。
现有代码快速修复
如果是你当前写死两个tab的场景,直接在组件类中通过@ViewChild获取模板实例再返回即可:
- 组件类代码:
import { ViewChild, TemplateRef } from '@angular/core'; export class TabComponent { @ViewChild('tab1') tab1Tpl: TemplateRef<any>; @ViewChild('tab2') tab2Tpl: TemplateRef<any>; selectedTab = { selector: 'tab1' }; // 保留你的原有选中逻辑 getTemplate(): TemplateRef<any> { return this.selectedTab.selector === 'tab1' ? this.tab1Tpl : this.tab2Tpl; } }
- 模板部分不用修改,原有写法直接生效。
通用组件库适配方案
如果你要封装为通用tab组件,支持用户自定义任意数量的tab模板,推荐用@ContentChildren+自定义指令的方案,性能和扩展性都符合要求:
- 先定义Tab子指令,用于接收用户传入的每个tab的配置和模板:
// tab.directive.ts import { Directive, Input, TemplateRef } from '@angular/core'; @Directive({ selector: '[appTab]' }) export class TabDirective { @Input() tabTitle: string; // 直接挂载对用户传入模板的引用 constructor(public templateRef: TemplateRef<any>) {} }
- Tabs容器组件内部获取所有用户传入的tab实例:
// tabs.component.ts import { ContentChildren, QueryList } from '@angular/core'; import { TabDirective } from './tab.directive'; export class TabsComponent { // 获取用户传入的所有tab项 @ContentChildren(TabDirective) tabs: QueryList<TabDirective>; selectedTab: TabDirective; ngAfterContentInit() { // 默认选中第一个tab this.selectedTab = this.tabs.first; } selectTab(tab: TabDirective) { this.selectedTab = tab; } }
- Tabs组件模板写法:
<!-- tab标题导航 --> <div class="tab-nav"> <span *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab === selectedTab" > {{tab.tabTitle}} </span> </div> <!-- tab内容渲染区 --> <ng-container *ngTemplateOutlet="selectedTab?.templateRef"></ng-container>
- 用户调用组件的用法:
<app-tabs> <ng-template appTab tabTitle="Tab 1"> 用户自定义的Tab1内容,支持任意DOM结构 </ng-template> <ng-template appTab tabTitle="Tab 2"> 用户自定义的Tab2内容,完全由用户控制 </ng-template> <!-- 可扩展任意数量的tab项 --> </app-tabs>
该方案完全不需要用*ngIf实现,只有选中的tab才会渲染对应模板,初始渲染性能开销极低,同时所有逻辑都封装在组件内部,用户只需要按约定传入模板即可,符合通用组件库的设计要求。
内容的提问来源于stack exchange,提问作者Bonnie Hanks
相关产品推荐
相关产品推荐

