如何在Angular中使用Renderer2的appendChild方法结合TemplateRef
Angular自定义指令中如何追加TemplateRef到目标元素
问题场景
我正在开发一个自定义tooltip指令,需要将<ng-template>里的内容追加到tooltip元素中。当前代码可以成功追加文本,但尝试直接追加TemplateRef时触发错误。
HTML代码:
<ng-template #tooltipContent> <span>hello world</span> </ng-template> <button tooltipText="tooltip text" [appendedLinkElement]="tooltipContent" > </button>
指令代码(可正常追加文本的版本):
// ... @Directive({ selector: '[pslTooltip]', // ... }) export class TooltipDirective ... { @Input('tooltipText') tooltipText: string; @Input() appendedLinkElement: TemplateRef<any>; // ... constructor(private el: ElementRef, private renderer: Renderer2) { } create() { this.tooltip = this.renderer.createElement('span'); this.renderer.appendChild( this.tooltip, this.renderer.createText(this.tooltipText) // 此方法可行,但无法直接追加TemplateRef ); this.renderer.appendChild(document.body, this.tooltip); // ... } }
尝试直接追加TemplateRef时的错误代码及报错:
// 尝试追加`#tooltipContent` TemplateRef: this.renderer.appendChild( this.tooltip, this.appendedLinkElement, );
控制台报错:"TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'."
解决方案
问题核心:TemplateRef本身不是DOM节点,它只是Angular用于描述模板的引用,必须先通过ViewContainerRef将其实例化为嵌入视图,才能得到可操作的DOM节点。
修改步骤:
- 在指令构造函数中注入
ViewContainerRef - 使用
ViewContainerRef.createEmbeddedView()方法实例化TemplateRef,得到EmbeddedViewRef - 将嵌入视图的根节点(
rootNodes)追加到tooltip元素中
修改后的指令代码:
// ... import { ViewContainerRef, EmbeddedViewRef } from '@angular/core'; @Directive({ selector: '[pslTooltip]', // ... }) export class TooltipDirective ... { @Input('tooltipText') tooltipText: string; @Input() appendedLinkElement: TemplateRef<any>; // ... constructor( private el: ElementRef, private renderer: Renderer2, private viewContainerRef: ViewContainerRef // 注入ViewContainerRef ) { } create() { this.tooltip = this.renderer.createElement('span'); if (this.appendedLinkElement) { // 实例化TemplateRef为嵌入视图 const embeddedView: EmbeddedViewRef<any> = this.viewContainerRef.createEmbeddedView(this.appendedLinkElement); // 将嵌入视图的所有根节点追加到tooltip中 embeddedView.rootNodes.forEach(node => { this.renderer.appendChild(this.tooltip, node); }); } else { // 保留原有的文本追加逻辑 this.renderer.appendChild( this.tooltip, this.renderer.createText(this.tooltipText) ); } this.renderer.appendChild(document.body, this.tooltip); // ... } }
代码说明
createEmbeddedView()会根据TemplateRef生成对应的DOM元素,返回的EmbeddedViewRef的rootNodes属性包含了所有实例化后的DOM节点- 遍历
rootNodes逐个追加,确保模板中的所有元素都被正确添加到tooltip容器中 - 保留原有的文本逻辑,实现文本和模板内容的兼容处理
内容的提问来源于stack exchange,提问作者JimmyTheCode
相关产品推荐
相关产品推荐

