动态组件加载器 (与vue的动态组件的应用场景类似)
译注:本页讲的是一个用于显示广告的范例,而部分广告拦截器插件,比如 Chrome 的 AdGuard,可能会破坏其工作逻辑,因此,请在本页关闭那些插件。
我的理解: 这个demo将指令绑定在,通过指令的viewContainerRef能够获取宿主元素,再通过ComponentFactoryResolver 来为每个具体的组件解析出一个 ComponentFactory。 然后 ComponentFactory 会为每一个组件创建一个实例。最后通过取宿主元素替换其中的内容或者说引用不同的组件
这个demo我是写在components模块里面,也将当前模块的index.module.ts代码粘贴出来
相关代码
/* dynamic-source.service.ts 获取数据的service*/
import { Injectable } from '@angular/core';
import { DynamicComponentOneComponent } from './component-1';
import { DynamicComponentTwoComponent } from './component-2';
import { DynamicComponentThreeComponent } from './component-3';
class DynamicComponent {
components: any;
data: any;
constructor(components: any, data: any) {
this.components = components;
this.data = data;
}
}
@Injectable()
export class DynamicSourceService {
getComponents() {
return [
new DynamicComponent(DynamicComponentOneComponent, {
name: 'app-dynamic-component-1',
age: 'Brave as they come',
}),
new DynamicComponent(DynamicComponentTwoComponent, {
name: 'app-dynamic-component-2',
age: 'Brave as they come',
}),
new DynamicComponent(DynamicComponentThreeComponent, {
name: 'app-dynamic-component-3',
age: 'Brave as they come',
}),
];
}
}
/*
dynamic.directive.ts 绑定到 <ng-template></ng-template>
要在当前模块中声明该指令
@NgModule({
declarations: [
DynamicComponent,
DynamicDirective,
],
})
*/
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[adHost]',
})
export class DynamicDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}
/* dynamic-component.ts 看到的界面*/
import {
Component,
ComponentFactoryResolver,
OnInit,
AfterViewInit,
ViewChild,
} from '@angular/core';
import { DynamicSourceService } from './dynamic-source.service';
import { DynamicDirective } from './dynamic.directive';
@Component({
selector: 'dynamic-component',
template: `
<div class="dynamic-component">
<h1 #adHost>app-dynamic-component</h1>
<ng-template adHost></ng-template>
<button (click)="loadingComponent(0)">app-dynamic-component-1</button>
<button (click)="loadingComponent(1)">app-dynamic-component-2</button>
<button (click)="loadingComponent(2)">app-dynamic-component-3</button>
</div>
`,
providers: [DynamicSourceService],
})
export class DynamicComponent implements AfterViewInit {
components: any[] = [];
@ViewChild(DynamicDirective) adHost!: DynamicDirective;
constructor(
private dynamicSourceService: DynamicSourceService,
private componentFactoryResolver: ComponentFactoryResolver
) {}
ngAfterViewInit() {
this.components = this.dynamicSourceService.getComponents();
this.loadingComponent(0);
// this returns null
}
loadingComponent(index:number) {
const component = this.components[index];
const ComponentFactory = this.componentFactoryResolver.resolveComponentFactory(
component.components
);
const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear()
const newComponent = viewContainerRef.createComponent<any>(
ComponentFactory
);
setTimeout(() => {
newComponent.instance.data = component.data;
}, 0);
}
}
/*
当前模块的modlue index.module.ts
引入指令 组件 等
*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
// 组件导入
import { AppComponentsComponent } from './index.component';
import { SpecialSelectorsParentComponent } from './components-css/special-selectors-host'
import { SpecialSelectorsChilrenComponent } from './components-css/special-selectors-host'
import { SpecialSelectorsHostContextParentComponent } from './components-css/special-selectors-host-context'
import { SpecialSelectorsHostContextChilrenComponent } from './components-css/special-selectors-host-context'
import { SpecialSelectorsDeepParentComponent } from './components-css/special-selectors-deep'
import { SpecialSelectorsDeepChilrenComponent } from './components-css/special-selectors-deep'
import {DynamicComponent} from './component-dynamic/dynamic-component'
import {DynamicDirective } from '../components/component-dynamic/dynamic.directive'
import {DynamicComponentOneComponent} from './component-dynamic/component-1'
import {DynamicComponentTwoComponent} from './component-dynamic/component-2'
import {DynamicComponentThreeComponent} from './component-dynamic/component-3'
import {PopupComponent} from './components-angular-element/popup.component'
import {AngularElementComponent} from './components-angular-element/angular-element.component'
// 路由导入
import { ComponentsRoutingModule } from './index-routing.module';
@NgModule({
declarations: [
AppComponentsComponent,
SpecialSelectorsParentComponent,
SpecialSelectorsChilrenComponent,
SpecialSelectorsHostContextParentComponent,
SpecialSelectorsHostContextChilrenComponent,
SpecialSelectorsDeepParentComponent,
SpecialSelectorsDeepChilrenComponent,
DynamicComponent,
DynamicDirective,
DynamicComponentOneComponent,
DynamicComponentTwoComponent,
DynamicComponentThreeComponent,
PopupComponent,
AngularElementComponent
],
imports: [
CommonModule,
FormsModule,
RouterModule,
ComponentsRoutingModule,
],
})
export class AppComponentsModule { }