Angular中是否有必要按需动态获取ng-template模板引用?
问题描述
我在Base组件中声明了一个summary模板,所属表单组件共包含4个标签页,仅当用户点击最后一个标签页时才会渲染该summary模板。请问是否有必要仅在用户点击最后一个标签页时才获取该summary模板的TemplateRef引用?这种实现方式有什么优势?
相关代码
Base组件代码
<!-- 模板部分 --> <ng-template #appSummary let-summary>xx</ng-template>
// 类方法 getAppSummaryRef(): TemplateRef<any> { return this.appSummary ; }
表单组件写法1(动态获取引用)
constructor(){ this.lastTab$.pipe(distinctUntilChanged()).subscribe((summaryTab: any) => { this.summaryRef = !!summaryTab ? this.baseComp.getAppSummaryRef() : null; }); }
表单组件写法2(构造函数直接获取引用)
constructor(){ this.summaryRef = this.baseComp.getAppSummaryRef(); }
回答
没有必要特意实现写法1的动态获取/置空逻辑,常规场景下写法2的直接获取方式就够用,甚至更稳妥。
首先要明确TemplateRef的本质:它是Angular编译模板阶段生成的、指向<ng-template>定义的轻量引用对象,本身不持有渲染后的组件/DOM实例,也不会触发模板内部的逻辑执行。只要Base组件完成初始化,这个引用就是固定存在的,提前拿到存储也不会产生任何额外性能开销。
很多人认为动态获取更省性能,本质是认知误区:
- 从你贴的代码来看,
#appSummary是直接声明在Base组件根模板下的,没有被*ngIf等结构性指令包裹,只要Base组件不销毁,对应的TemplateRef实例就会一直存在。你在表单组件切tab时把summaryRef设为null,根本不会触发这个对象的垃圾回收,完全是无效操作。 - 模板内部的内容只有在实际通过
*ngTemplateOutlet渲染、或者手动调用createEmbeddedView创建嵌入视图时才会被实例化。不管你多早拿到TemplateRef,只要不执行渲染操作,就不会生成DOM、不会执行模板内的绑定逻辑,完全不存在“提前加载”的额外开销。
反过来写法1还会平白增加问题风险:
- 你需要额外维护一个订阅流,还要手动处理订阅的生命周期避免内存泄漏;
- 一旦tab切换事件和模板渲染的时机没有对齐,很容易出现切到最后一个tab时
summaryRef仍为null,导致summary区域渲染空白的异常。
只有一种场景需要用动态获取的逻辑:如果#appSummary模板本身被结构性指令包裹,比如它直接放在最后一个标签页的容器内部,未切到最后tab时这个ng-template本身都没有被初始化,构造函数阶段获取会拿到undefined,这时候才需要等模板存在后再获取引用。你当前的代码场景不满足这个前提,不需要多此一举。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

