摘要:最近接手了一個項目,客戶提出了一個高大上的需求要求只有一個主界面,所有組件通過來顯示。
最近接手了一個項目,客戶提出了一個高大上的需求:要求只有一個主界面,所有組件通過Tab來顯示。其實這個需求并不詭異,不喜歡界面跳轉的客戶都非常熱衷于這種展現形式。
好吧,客戶至上,搞定它!這種實現方式在傳統的HTML應用中,非常簡單,只是在這Angular4(以下簡稱ng)中,咋個弄呢?
我們先來了解下ng中動態加載組件的兩種方式:
加載已經聲明的組件: 使用ComponentFactoryResolver,將一個組件實例呈現到另一個組件視圖上;
動態創建組件并加載:使用ComponentFactory和Compiler,創建和呈現組件
根據我們的需求,各個組件是事先開發好的,需要在同一個組件上顯示出來。所以第一種方式符合我們的要求。
使用ComponentFactoryResolver動態加載組件,需要先了解如下概念:
ViewChild:屬性裝飾器,通過它可以獲得視圖上對應的元素;
ViewContainerRef:視圖容器,可在其上創建、刪除組件;
ComponentFactoryResolver:組件解析器,可以將一個組件呈現在另一個組件的視圖上。
搞明白了概念,看看代碼吧:
//// HTML代碼
//// ts代碼 import {Component, Input, ViewContainerRef, ViewChild, ComponentFactoryResolver,ComponentRef,OnDestroy,OnInit} from "@angular/core"; import {RoleComponent} from "./role/role.component"; @Component({ selector: "dynamic-container", entryComponents: [RoleComponent,....], //需要動態加載的組件名,這里一定要指定,否則報錯 template: "" }) export class DynamicComponent implements OnDestroy,OnInit { @ViewChild("container", { read: ViewContainerRef }) container: ViewContainerRef; @Input() componentName //需要加載的組件名 compRef: ComponentRef ; // 加載的組件實例 constructor(private resolver: ComponentFactoryResolver) {} loadComponent() { let factory = this.resolver.resolveComponentFactory(this.componentName); if (this.compRef) { this.compRef.destroy(); } this.compRef = this.container.createComponent(factory) //創建組件 } ngAfterContentInit() { this.loadComponent() } ngOnDestroy() { if(this.compRef){ this.compRef.destroy(); } } }
代碼的確不復雜!
可是,如果加載的組件有傳入的參數,比如修改角色組件,需要傳入角色id,該怎么辦呢?有辦法解決,使用ReflectiveInjector(依賴注入),在加載組件時將需要傳入的參數注入到組件中。代碼調整如下:
//// HTML代碼,增加了inputs參數,其值為參數值對
//// ts代碼 import { ReflectiveInjector} from "@angular/core"; ...... export class DynamicComponent implements OnDestroy,OnInit { @Input() inputs:any //加載組件需要傳入的參數組 ....... loadComponent() { let factory = this.resolver.resolveComponentFactory(this.componentName); if(!this.inputs) this.inputs={} let inputProviders = Object.keys(this.inputs).map((inputName) => { return {provide: inputName, useValue: this.inputs[inputName]};}); let resolvedInputs = ReflectiveInjector.resolve(inputProviders); let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.container.parentInjector); if (this.compRef) { this.compRef.destroy(); } this.compRef = factory.create(injector) //創建帶參數的組件 this.container.insert(this.compRef.hostView);//呈現組件的視圖 } ngAfterContentInit() { this.loadComponent() } ...... } ////RoleComponent代碼如下 export class RoleComponent implements OnInit { myName:string ........ constructor(){ //this.myName的值為dynamic } }
到此,動態加載組件的界面驕傲滴顯示在界面上。等等,貌似哪里不對!為什么界面上從后臺獲取的數據沒有加載?
獲取數據的代碼如下:
export class RoleComponent implements OnInit { roleList=[]; ...... constructor(private _roleService.list:RoleService) { this._roleService.list().subscribe(res=>{ this.roleList=res.roleList; }); } ...... }
經過反復測試,得出結論如下:從后臺通過HTTP獲取的數據已經獲得,只是沒有觸發ng進行變更檢測,所以界面沒有渲染出數據。
抱著“遇坑填坑”的信念,研習ng的文檔,發現ng支持手動觸發變更檢測,只要在適當的位置調用變更檢測即可。同時,ng提供了不同級別的變更檢測:
變更檢測策略:
Default :ng提供的Default的檢測策略,只要組件的input發生改變,就觸發檢測; OnPush :OnPush檢測策略是input發生改變,并不立即觸發檢測,而是輸入的引用發生變化時,才會觸發檢測。
ChangeDetectorRef.detectChanges():可顯式的控制變更檢測,在需要的地方使用即可;
NgZone.run():在整個應用中進行變更檢測
ApplicationRef.tick():在整個應用中進行變更檢測,偵聽NgZone的onTurnDone事件,來觸發檢測
根據文檔顯示,ng應用缺省就在使用NgZone來檢測變更,這對于正常加載的組件是沒有問題的,但是對于動態加載的組件卻不起作用。幾次試驗下來,唯有第二種方法起作用:顯式調用ChangeDetectorRef.detectChanges()
于是修改ts代碼:
interval:any loadComponent() { ...... this.interval=setInterval(() => { this.compRef.changeDetectorRef.detectChanges(); }, 50); //50毫秒檢測一次變更 } ngOnDestroy() { ...... clearInterval(this.interval) }
鑒于本人的ng技能尚淺,就用這種笨拙的方法解決了數據加載問題,但是如鯁在喉,總覺應該還有更優雅的解決方法,待我再花時日研究下。
啰嗦至此,文中如有不妥之處,歡迎各位看官指正。
補充一句,強烈推薦PrimeNG,它提供了豐富的前端組件,可以方便取用,大大節省了界面的開發速度。
參考文獻:
Angular 2 Change Detection, Zones and an example
Angular change detection explained
深入理解Angular2變化監測和ngZone
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83891.html
摘要:的特性和性能是的超集,用于幫助的開發。注解提供了連接元數據和功能的工具。通過在庫中提供基本信息可以調用函數或創建類的實例來檢查相關元數據,從而簡化了對象實例的構建。停用它會響應跳出舊控制器的成功事件。 showImg(https://segmentfault.com/img/bVSqTU?w=850&h=460); 在Web應用開發領域,Angular被認為是最好的開源JavaScri...
摘要:缺乏高級編程特性影響同樣深遠,社區發展的預處理器能夠有效緩解,,,殊途同歸,異軍突起,基本實現變量嵌套變量混合擴展和邏輯等。 前言 關注點分離(separation of concerns)原則多年來大行其道,實踐中一般將 HTML、CSS、JavaScript 分開編寫維護,早期框架 angularjs 即是如此,直到 React 爭議中問世,引領關注點混合趨勢,驅使開發者重新審視 ...
摘要:上一節解決了用戶注冊和登錄數據部分的內容。這一節開始分析用戶模塊用戶路由。用戶管理模塊分析主要代碼如下數組中,是構建子組件必須引入的模塊。當點擊標簽時,根據路由定義直接跳轉到組件,進行用戶的注冊操作。 上一節解決了用戶注冊和登錄數據部分的內容。這一節開始分析用戶模塊、用戶路由。## 用戶管理模塊UserModule分析 ##UserModule主要代碼如下: import { NgMo...
閱讀 2285·2021-11-15 11:37
閱讀 2954·2021-09-01 10:41
閱讀 787·2019-12-27 11:58
閱讀 747·2019-08-30 15:54
閱讀 715·2019-08-30 13:52
閱讀 2930·2019-08-29 12:22
閱讀 1075·2019-08-28 18:27
閱讀 1452·2019-08-26 18:42