angular 16 动态生成组件
需求
在页面中生成一个确认弹窗
新的实现方式
第一步,获取需要的工具
@Injectable({
providedIn: 'root'
})
export class DialogService {
public containerRef: ViewContainerRef; //需要从Component中获取,然后传递进来
constructor(
private injector: Injector,
) { }
}
ViewContainerRef 的获取方式
-
第一种在
Component
初始化时获取 -
在
template
中通过ng-container
获取@Component({ selector: 'app-dialog-container', template: '<ng-container #modalVC></ng-container>', styles: [''], }) export class DialogContainerComponent implements AfterViewInit { @ViewChild('modalVC', {read: ViewContainerRef}) private viewContainerRef: ViewContainerRef; constructor( private service: DialogService, ) { } ngAfterViewInit(): void { this.service.containerRef = this.viewContainerRef; } }
主要区别:就是增加的元素节点为兄弟节点,所以,第一种添加的弹窗是在外面的,不受 app-dialog-container
中的样式影响;第二种是作为子元素添加的,受样式影响
第二步,实现动态生成组件
component
为组件的类名
const dialogRef = this.containerRef.createComponent(component, {
injector: this.injector
});
// dialogRef.instance 就是组件的实例
第三步,移除组件
如果需要在组件初始化,自动注入值或传值,则需要自定义 injector
import { InjectFlags, Injector, ProviderToken } from '@angular/core';
// 这个类是传值的载体
export class DialogPackage<T = any> {
constructor(
public data: T,
public dialogId: any,
) {
}
}
// 这是自定义的注射器
export class DialogInjector<T> implements Injector {
constructor(
private data: DialogPackage,
private parentInjector: Injector
) {}
get<T>(token: ProviderToken<T>, notFoundValue?: T, option?: InjectOptions): T;
get(token: any, notFoundValue?: any);
get(token: any, notFoundValue?: any, flags?: any): any {
if (token === DialogPackage) {
return this.data;
}
return this.parentInjector.get<T>(token, notFoundValue, flags);
}
}
则第二步
需要修改
const dialogInjector = new DialogInjector(new DialogPackage(option, dialogId), this.injector);
const dialogRef = this.containerRef.createComponent(component, {
injector: dialogInjector
});
// dialogRef.instance 就是组件的实例
在组件中接收值
export class DialogConfirmComponent {
constructor(
private data: DialogPackage<DialogConfirmOption>,
private service: DialogService,
) {
}
}
过时实现代码
第一步,获取需要的工具
export class DialogService {
constructor(
private resolver: ComponentFactoryResolver,
private applicationRef: ApplicationRef,
private injector: Injector,
@Inject(DOCUMENT) private document: Document,
) { }
}
第二步,实现动态生成组件
component
为组件的类名
const dialogFactory = this.resolver.resolveComponentFactory(component);
const dialogRef = dialogFactory.create(this.injector);
// 正式添加到程序和添加到页面上,才能显示
this.applicationRef.attachView(dialogRef.hostView);
this.document.body.appendChild(dialogRef.location.nativeElement);
// dialogRef.instance 就是组件的实例
第三步,移除组件
this.applicationRef.detachView(dialogRef.hostView);
this.document.body.removeChild(dialogRef.location.nativeElement);
如果需要在组件初始化,自动注入值或传值,则需要自定义 injector
import { InjectFlags, Injector, ProviderToken } from '@angular/core';
// 这个类是传值的载体
export class DialogPackage<T = any> {
constructor(
public data: T,
public dialogId: any,
) {
}
}
// 这是自定义的注射器
export class DialogInjector<T> implements Injector {
constructor(
private data: DialogPackage,
private parentInjector: Injector
) {}
get<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
get(token: any, notFoundValue?: any);
get(token: any, notFoundValue?: any, flags?: any): any {
if (token === DialogPackage) {
return this.data;
}
return this.parentInjector.get<T>(token, notFoundValue, flags);
}
}
则第二步
需要修改
const dialogFactory = this.resolver.resolveComponentFactory(component);
// 这里的option 可以是任何值
const dialogInjector = new DialogInjector(new DialogPackage(option, dialogId), this.injector);
const dialogRef = dialogFactory.create(dialogInjector);
// 正式添加到程序和添加到页面上,才能显示
this.applicationRef.attachView(dialogRef.hostView);
this.document.body.appendChild(dialogRef.location.nativeElement);
// dialogRef.instance 就是组件的实例
在组件中接收值
export class DialogConfirmComponent {
constructor(
private data: DialogPackage<DialogConfirmOption>,
private service: DialogService,
) {
}
}
转载请保留原文链接: https://zodream.cn/blog/id/212.html