如果像我这样的人现在仍在寻找一个简单而清晰的解决方案 - 就在这里。我从@angular/cdk https://github.com/angular/components/tree/master/src/cdk得到它
并做了一个简单的服务。
import {
Injectable,
ApplicationRef,
ComponentFactoryResolver,
ComponentRef,
Injector,
EmbeddedViewRef
} from '@angular/core';
export type ComponentType<T> = new (...args: any[]) => T;
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor(
private _appRef: ApplicationRef,
private _resolver: ComponentFactoryResolver,
private _injector: Injector
) { }
private _components: ComponentRef<any>[] = [];
add<T>(
component: ComponentType<T> | ComponentRef<T>,
element?: Element | string
): ComponentRef<T> {
const componentRef = component instanceof ComponentRef
? component
: this._resolver.resolveComponentFactory(component).create(this._injector);
this._appRef.attachView(componentRef.hostView);
if (typeof element === 'string') {
element = document.querySelector(element);
}
if (!element) {
element = document.body;
}
element.appendChild(
(componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement
);
this._components.push(componentRef);
return componentRef;
}
remove(dialog: number | ComponentRef<any>): boolean {
let componentRef;
if (typeof dialog === 'number' && this._components.length > dialog) {
componentRef = this._components.splice(dialog, 1)[0];
}
else {
for (const cr of this._components) {
if (cr === dialog) {
componentRef = cr;
}
}
}
if (componentRef) {
this._remove(componentRef);
return true;
}
return false;
}
private _remove(componentRef: ComponentRef<any>) {
this._appRef.detachView(componentRef.hostView);
componentRef.destroy();
}
clear() {
while (this._components.length > 0) {
this._remove(this._components.pop());
}
}
getIndex(componentRef: ComponentRef<any>): number {
return this._components.indexOf(componentRef);
}
}
您可以将 ComponentClass 或 ComponentRef 传递给add
和 Element 或任何 querySelector 字符串,该字符串指向您想要将组件作为第二个参数附加到的任何 DOM 元素(或不传递任何内容,然后假定您要附加到正文)。
const cr = this._service.add(MyComponent); // will create MyComponent and attach it to document.body or
const cr = this._service.add(MyComponent, this.someElement); // to attach to Element stored in this.someElement or
const cr = this._service.add(MyComponent, 'body div.my-class > div.my-other-div'); // to search for that element and attach to it
const crIndex = this._service.getIndex(cr);
cr.instance.myInputProperty = 42;
cr.instance.myOutputEmitter.subscribe(
() => {
// do something then for example remove this component
this._service.remove(cr);
}
);
this._service.remove(crIndex); // remove by index or
this._service.remove(cr); // remove by reference or
this._service.clear(); // remove all dynamically created components
PS不要忘记将您的动态组件添加entryComponents: []
到@NgModule