如何在不使用废弃API的情况下将Angular组件挂载到document body?
Angular 无废弃API实现组件渲染为body直接子元素
我希望将一个Angular组件(浮层)渲染为document <body>元素的直接子元素。原先通过ComponentFactoryResolver实现的代码如下,但该API在Angular 13中已废弃,Angular 16可能会移除:
constructor( private applicationRef: ApplicationRef, private componentFactoryResolver: ComponentFactoryResolver, @Inject(DOCUMENT) private document: Document, private injector: Injector ) {} public renderOverlayInBody(): void { const overlayRef = this.componentFactoryResolver .resolveComponentFactory(OverlayComponent) .create(this.injector); this.applicationRef.attachView(overlayRef.hostView); const overlayRoot = (overlayRef.hostView as EmbeddedViewRef<unknown>) .rootNodes[0] as HTMLElement; // 将组件挂载到body下 this.document.body.appendChild(overlayRoot); }
官方推荐的替代方案ViewContainerRef.createComponent只能将组件挂载到当前组件的视图容器内,无法直接挂到body下:
constructor(private viewContainerRef: ViewContainerRef) {} public ngOnInit(): void { // 仅能挂载到当前组件的视图容器中 this.viewContainerRef.createComponent(OverlayComponent); }
以下是两种不依赖废弃API的实现方式:
方法一:手动创建组件并挂载到body
可以通过组件类的create静态方法直接创建实例,再将其关联到应用视图树并挂载到body:
import { ApplicationRef, Inject, Injector, DOCUMENT } from '@angular/core'; import { OverlayComponent } from './overlay.component'; @Component({/* 组件元数据 */}) export class AppComponent { constructor( private appRef: ApplicationRef, private injector: Injector, @Inject(DOCUMENT) private document: Document ) {} renderOverlayToBody(): void { // 创建OverlayComponent实例 const componentRef = OverlayComponent.create(this.injector); // 将组件视图附加到应用,确保变更检测正常工作 this.appRef.attachView(componentRef.hostView); // 获取组件的根DOM节点,挂载到body const rootElement = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement; this.document.body.appendChild(rootElement); // 组件销毁时,从应用视图树中移除,避免内存泄漏 componentRef.onDestroy(() => { this.appRef.detachView(componentRef.hostView); }); } }
方法二:使用Angular CDK Overlay模块(推荐)
如果是开发浮层类组件,Angular CDK的Overlay模块是官方最优解,它原生支持将浮层挂载到body,还提供了定位、遮罩、交互等成熟能力:
- 导入Overlay模块到你的NgModule:
// app.module.ts import { OverlayModule } from '@angular/cdk/overlay'; @NgModule({ imports: [/* 其他模块 */, OverlayModule] }) export class AppModule {}
- 在组件中创建并挂载浮层:
import { Overlay, OverlayConfig } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import { OverlayComponent } from './overlay.component'; @Component({/* 组件元数据 */}) export class AppComponent { constructor(private overlay: Overlay) {} openOverlay(): void { // 配置浮层:挂载到全局(body下),添加遮罩,居中显示 const overlayConfig = new OverlayConfig({ hasBackdrop: true, positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically() }); // 创建浮层实例 const overlayRef = this.overlay.create(overlayConfig); // 将OverlayComponent挂载到浮层中 overlayRef.attach(new ComponentPortal(OverlayComponent)); // 点击遮罩关闭浮层并销毁实例 overlayRef.backdropClick().subscribe(() => overlayRef.dispose()); } }
内容的提问来源于stack exchange,提问作者kremerd
相关产品推荐
相关产品推荐

