默认的ViewContainerRef
如何在全局创建一个 ViewContainerRef?
Angular 中的 Component,Template 都得存在于 VD 中的一个 ViewContainer 里面。在基于 CDK 的 overlay 通过编程的方式来打开一个 template 的时候,需要指定一个 ViewContainerRef,每一次这个都是由调用者传递过来,但是,我们仅仅是用它存放一下 template, 而 template 的实际的 Dom 却是由我们自己接管,放置到顶层的。那么既然这个 ViewContainerRef,是这个作用,我们能否获取这么个默认的 ViewContainerRef 呢?
找到一个方案,就是编写一个组件,在组件内部明确的获取一个 ViewContainerRef,我们的代码只需要动态的创建这个组件就性了,而这个组件无需真正的挂到 Dom 上,只是存在于 VirtualDom 上。代码如下:
// 这个就是那个组件
@Component({
selector: "ad-virtualContainer",
template: `<ng-container #containerRef></ng-container>`,
})
export class AdVirtualViewContainer {
@ViewChild("containerRef", { read: ViewContainerRef })
viewContainer: ViewContainerRef;
}
let _internalViewContainerRef: ViewContainerRef = null;
export class DefaultViewContainerRefProps {
appRef: ApplicationRef;
factoryResolver: ComponentFactoryResolver;
injector: Injector;
}
// 这个就是获取ViewContianerRef的代码。第一次的时候我们会动态创建组件,但是组件没有挂Dom树。
export function getDefaultViewContainerRef({
appRef,
factoryResolver,
injector,
}: DefaultViewContainerRefProps): ViewContainerRef {
if (_internalViewContainerRef === null) {
const factory = factoryResolver.resolveComponentFactory(
AdVirtualViewContainer
);
const compRef = factory.create(injector);
compRef.changeDetectorRef.detectChanges();
appRef.attachView(compRef.hostView);
_internalViewContainerRef = compRef.instance.viewContainer;
}
return _internalViewContainerRef;
}
这个里面遇到个问题,当我们用 CDK 的 overlay 来弹框模板的时候,用上面的 ViewContainerRef 完全可以工作。但是,如果组件内部的 ViewContainerRef 是从构造函数注入的。那么这个时候,弹框能够打开,但是关闭的时候,模板的 DOM 没有销毁,一直没有找到原因。估计是在 cdk overlay 的关闭方式里面有问题。