Angular使用動態(tài)加載組件方法實(shí)現(xiàn)Dialog的示例
網(wǎng)上的文章和教程基本上寫到組件加載完成就沒了!沒了?!而且都是只能存在一個dialog,想要打開另一個dialog必須先銷毀當(dāng)前打開的dialog,之后看過 material 的實(shí)現(xiàn)方式,怪自己太蠢看不懂源碼,就只能用自己的方式來實(shí)現(xiàn)一個dialog組件了
Dialog組件的目標(biāo):可以同時存在多個Dialog,可銷毀指定Dialog,銷毀后html中無組件殘留且提供回調(diào)
動態(tài)加載組件的實(shí)現(xiàn)方式有兩種,angular4.0版本之前使用ComponentFactoryResolver來實(shí)現(xiàn),4.0之后可以使用更便捷的ngComponentOutlet來實(shí)現(xiàn),
通過ComponentFactoryResolver實(shí)現(xiàn)動態(tài)載入
首先理一下ViewChild、ViewChildren、ElementRef、ViewContainerRef、ViewRef、ComponentRef、ComponentFactoryResolver之間的關(guān)系:
ViewChild 與 ViewChildren
ViewChild是通過模板引用變量(#)或者指令(directive)用來獲取 Angular Dom 抽象類,ViewChild可以使用 ElementRef 或者 ViewContainerRef 進(jìn)行封裝。
@ViewChild('customerRef') customerRef:ElementRef;
ViewChildren通過模板引用變量或者指令用來獲取QueryList,像是多個ViewChild組成的數(shù)組。
@ViewChildren(ChildDirective) viewChildren: QueryList<ChildDirective>;
ElementRef 與 ViewContainerRef
ViewChild可以使用 ElementRef 或者 ViewContainerRef 進(jìn)行封裝,那么 ElementRef 和 ViewContainerRef 的區(qū)別是什么?
用 ElementRef 進(jìn)行封裝,然后通過 .nativeElement 來獲取原生Dom元素
console.log(this.customerRef.nativeElement.outerHTML);
ViewContainerRef :視圖的容器,包含創(chuàng)建視圖的方法和操作視圖的api(組件與模板共同定義了視圖)。api會返回 ComponentRef 與 ViewRef,那么這兩個又是什么?
// 使用ViewContainetRef時,請使用read聲明 @ViewChild('customerRef',{read: ViewContainerRef}) customerRef:ViewContainerRef; ··· this.customerRef.createComponent(componentFactory) // componentFactory之后會提到
ViewRef 與 ComponentRef
ViewRef 是最小的UI單元,ViewContainerRef api操作和獲取的就是ViewRef
ComponentRef:宿主視圖(組件實(shí)例視圖)通過 ViewContainerRef 創(chuàng)建的對組件視圖的引用,可以獲取組件的信息并調(diào)用組件的方法
ComponentFactoryResolver
要獲取 ComponentRef ,需要調(diào)用 ViewContainer 的 createComponent 方法,方法需要傳入ComponentFactoryResolver創(chuàng)建的參數(shù)
constructor( private componentFactoryResolver:ComponentFactoryResolver ) { } viewInit(){ componentFactory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent); // 獲取對組件視圖的引用,到這一步就已經(jīng)完成了組件的動態(tài)加載 componentRef = this.customerRef.createComponent(componentFactory); // 調(diào)用載入的組件的方法 componentRef.instance.dialogInit(component); }
具體實(shí)現(xiàn)
let componentFactory,componentRef;
@ViewChild('customerRef',{read: ViewContainerRef}) customerRef:ViewContainerRef; constructor( private componentFactoryResolver:ComponentFactoryResolver ) { } viewInit(){ // DialogComponent:你想要動態(tài)載入的組件,customerRef:動態(tài)組件存放的容器 componentFactory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent); componentRef = this.customerRef.createComponent(componentFactory); }
通過ngComponentOutlet實(shí)現(xiàn)動態(tài)載入
ngComponentOutlet 大大縮減了代碼量,但是只有帶4.0之后的版本才支持
具體實(shí)現(xiàn)
在dialog.component.html建立動態(tài)組件存放節(jié)點(diǎn)
<ng-container *ngComponentOutlet="componentName"></ng-container>
將組件(不是組件名稱)傳入,就OK了,為什么可以這么簡單!
dialogInit(component){ this.componentName = component; };
Dialog的實(shí)現(xiàn)
實(shí)現(xiàn)的思路是這樣的:首先創(chuàng)建一個dialog組件用來承載其他組件,為dialog創(chuàng)建遮罩和動畫,建立一個service來控制dialog的生成和銷毀,不過service只生成dialog,dialog內(nèi)的組件還是需要在dialog組件內(nèi)進(jìn)行生成
1、首先寫一個公共的service,用來獲取根組件的viewContainerRef(嘗試過 ApplicationRef 獲取根組件的 viewContainerRef 沒成功,所以就寫成service了)
gerRootNode(...rootNodeViewContainerRef){ if(rootNode){ return rootNode; }else { rootNode = rootNodeViewContainerRef[0]; }; } // 然后再根組件.ts內(nèi)調(diào)用 this.fn.gerRootNode(this.viewcontainerRef);
2、創(chuàng)建dialog.service.ts,定義open、close三個方法,使用ViewContainerRef創(chuàng)建dialog組件,創(chuàng)建之前需要調(diào)用 ComponentFactoryReslover,并將DialogComponent傳入
let componentFactory; let componentRef; @Injectable() export class DialogService { constructor( private componentFactoryResolver:ComponentFactoryResolver private fn:FnService ) { } open(component){ componentFactory = this.componentFactoryResolver.resolveComponentFactory(DialogComponent); // 這里的獲取的是ComponentRef containerRef = this.fn.gerRootNode().createComponent(componentFactory); // 將containerRef存儲下來,以便之后的銷毀 containerRefArray.push(containerRef); // 調(diào)用了組件內(nèi)的初始化方法,后面會提到 return containerRef.instance.dialogInit(component,containerRef); } // 這里有兩種情況,一種是在當(dāng)前組件和dialog組件關(guān)閉調(diào)用的,因?yàn)橛蟹祷刂邓钥梢躁P(guān)閉指定的dialog;還有一種是在插入到dialog組件內(nèi)的組件調(diào)用的,因?yàn)椴恢栏附M件的信息,所以默認(rèn)關(guān)閉最后一個dialog close(_containerRef=null){ if( _containerRef ){ return _containerRef.containerRef.instance.dialogDestory(); }else{ containerRefArray.splice(-1,1)[0].instance.dialogDestory(); } } }
3、dialog.component.ts,這里使用 ngComponentOutlet 來實(shí)現(xiàn)(ngComponentOutlet 在下面提到,這里為了偷懶,直接拿來用了)
let containerRef,dialogRef = new DialogRef(); export class DialogComponent implements OnInit { componentName; constructor( private fn:FnService ) { } dialogInit( _component, _containerRef){ this.componentName = _component; containerRef = _containerRef; dialogRef['containerRef'] = containerRef; return dialogRef; }; dialogDestory(){ let rootNode = this.fn.gerRootNode(); // 等待動畫結(jié)束再移除 setTimeout(()=>{ // 這里用到了 viewContainerRef 里的indexOf 和 remove 方法 rootNode.remove(rootNode.indexOf(containerRef.hostView)); },400); dialogRef.close(); return true; }; }
4、這里還創(chuàng)建了一個 DialogRef 的類,用來處理 dialog 關(guān)閉后的回調(diào),這樣就可以使用 XX.afterClose().subscribe() 來創(chuàng)建回調(diào)的方法了
@Injectable() export class DialogRef{ public afterClose$ = new Subject(); constructor(){} close(){ this.afterClose$.next(); this.afterClose$.complete(); } afterClose(){ return this.afterClose$.asObservable(); } }
創(chuàng)建和銷毀dialog
// 創(chuàng)建 let _viewRef = this.dialogService.open(DialogTestComponent); _viewRef.afterClose().subscribe(()=>{ console.log('hi'); }); // 銷毀 this.dialogService.close()
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
分享使用AngularJS創(chuàng)建應(yīng)用的5個框架
如果你計(jì)劃使用AngularJS創(chuàng)建你的Web應(yīng)用,那現(xiàn)在就開始吧。你不需要有任何的恐懼和擔(dān)心,因?yàn)楝F(xiàn)在有很多的框架都可以很好地支持AngularJS2015-12-12angularjs實(shí)現(xiàn)搜索的關(guān)鍵字在正文中高亮出來
這篇文章主要介紹了angularjs實(shí)現(xiàn)搜索的關(guān)鍵字在正文中高亮出來,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06ionic3+Angular4實(shí)現(xiàn)接口請求及本地json文件讀取示例
本篇文章主要介紹了ionic3+Angular4實(shí)現(xiàn)接口請求及本地json文件讀取示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10angular.js+node.js實(shí)現(xiàn)下載圖片處理詳解
這篇文章主要介紹了angular.js+node.js實(shí)現(xiàn)下載圖片處理的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03快速解決angularJS中用post方法時后臺拿不到值的問題
今天小編就為大家分享一篇快速解決angularJS中用post方法時后臺拿不到值的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08AngularJS中一般函數(shù)參數(shù)傳遞用法分析
這篇文章主要介紹了AngularJS中一般函數(shù)參數(shù)傳遞用法,結(jié)合實(shí)例形式分析了模型參數(shù)與普通參數(shù)的具體功能與使用技巧,需要的朋友可以參考下2016-11-11