🌊 實現
模擬場景:頁面上"幫助"按鈕的點擊觸發幫助文檔的彈出框,且每個頁面的幫助文檔不一樣
因此彈出框里的幫助文檔是一個動態模板而不是動態組件
以下comp均代表Type類型的動態組件,即 comp:Type<any>
//xx.component.ts export class xxComponent implements Oninit{ constructor(private helpingService:HelpingService){ } fireClick($event:any){//按鈕的點擊事件 this.helpingService.changeHelpContent(comp); } }
//helping.service.ts
@Injectable()
export class HelpingService{ helpChangeEvent:EventEmitter<comp>; constractor(){ this.helpChangeEvent=new EventEmitter<comp>() } public changeHelpContent(comp){ this.helpChangeEvent.emit(comp)//發射helpChangeEvent事件 }
}
//helping.component.ts @component({ selector: 'helping', templateUrl: './helping.component.html', styleUrls: ['./helping.component.scss'] }) @ViewChild('con',{read:ViewContainerRef}) conRef:ViewContainerRef; export class HelpingComponent implements OnInit{ constractor(private helpingService:HelpingService, private factoryResolver: ComponentFactoryResolver,){ this.helpingService.helpchangeEvent.subscribe((comp)=>{//接收helpChangeEvent事件 this.loadComponent(comp) }) } private loadComponent(comp){ this.conRef.clear();//刪除之前的視圖 let factory=this.factoryResolver.resolveComponentFactory(comp);//factory創建組件的實例 this.conRef.createComponent(factory) } }
✨ 動態創建組件的相關知識點
1.TemplateRef
通過TemplateRef實例,可以創建內嵌視圖Embedded Views
涉及對象和相關方法:
1.crateEbeddedView:創建內嵌視圖
@Component({ selector:'helping', template:`//創建組件,那組件內容就是固定的 <template #tpl> <span>i am a span in Template {{name}}</span> </template> ` }) export class helpingComponent{ @ViewChild('tpl') tpl:TemplateRef<any>; name:string='Artimis'; ngAfterViewInit(){ let view=this.tpl.createEmbeddedView(null); let commentEle=this.tpl.elementRef.nativeElement; view.rootNodes.forEach((node)=>{//沒有ViewContainerRef,只能手動把元素塞到視圖里 commentEle.parentNode.insertBefore(node,commentEle.nextSibling) }) } }
2.VIiewContainerRef
視圖容器,是管理創建好的內嵌視圖或組件視圖
通過ViewContainerRef實例,基於TemplateRef + createEmbeddedView創建內嵌視圖
@Component({ selector:'helping', template:` <template #tpl> <span>i am a span in Template {{name}}</span> </template> ` }) export class helpingComponent{ @ViewChild('tpl') tpl:TemplateRef<any>; @ViewChild('tpl',{read:ViewContainerRef}) tplVcRef:ViewContainerRef; name:string='Artimis'; ngAfterViewInit(){ //有ViewContainerRef,直接通過createEmbeddedView方法塞進視圖 this.tplVcRef.createEmbeddedView(this.tplRef) }
✨ 動態創建模板的相關知識點
1.ComponentFactoryResolver
通過ViewContainerRef實例,基於ComponentFactoryResolver + createComponent 創建模板視圖
涉及對象和相關方法:
1. ComponentFactoryResolver:一個服務對象(需要注入)
2. resolveComponentFactory:ComponentFactoryResolver的方法,接收一個組件類作為參數,返回一個ComponentFactory實例
3.createComponent:ViewContainerRef的方法,內部會調用ComponentFactory實例的create方法創建對應組件,並將組件添加到容器內
export abstract class ComponentFactoryResolver{ static NULL:ComponentFactoryResolver=new _NullComponentFactoryResolver(); abstract resolverComponentFactory<T>(component:Type<T>):ComponentFactory<T> }
@Component({ selector:'helping', template:`//創建模板,那模板的內容就不是固定的 <ng-container #con></ng-container> ` }) export class helpingComponent{ @ViewChild('con',{read:ViewContainerRef}) conRef:ViewContainerRef; constractor(private factoryResolver: ComponentFactoryResolver, private helpingService: HelpingService){ this.helpingService.manualChange.subscribe((comp)=>{ this.loadComp(comp); }) private loadComp(comp){ this.conRef.clear();//刪除之前的視圖 let factory=this.factoryResolver.resolveComponentFactory(comp);//factory是一個如何創建組件的實例 this.conRef.createComponent(factory) } }