angular2(4) 中動態(tài)創(chuàng)建組件的兩種方案

上例子:https://github.com/wuzhouyang/angular-dynamic-component-example

接觸 angular2 也有好幾月了译柏,由于在做的項目dom的操作貌似比較頻繁厉膀,而且并不能針對dom來編程,這樣的話與模板的耦合度便十分大傀蚌,所以只能針對組件編程,動態(tài)加載組件來實現(xiàn)項目中相關(guān)的功能只估,那就不得不用到angular2中一些比較低等級的api霸株。此文要記錄的便是目前用到的兩種動態(tài)創(chuàng)建組件的方案诸衔。

(一)動態(tài)加載已經(jīng)聲明的組件

針對我的項目場景:用戶拖動相關(guān)的塊到特定區(qū)域,區(qū)域中便會生成相應(yīng)的UI控件颇玷,此UI控件有自己的模板笨农、行為等等。生成UI 后便會在區(qū)域中顯示出來帖渠。所以我覺得將UI控件封為一個小組件谒亦,再動態(tài)加載,是個不錯的方案空郊。angular2中是如何動態(tài)加載組件的份招?

要實現(xiàn)這個功能,得先簡單了解angular2 中相關(guān)的api

  • ViewChild:一個屬性裝飾器狞甚,用來從模板視圖中獲取對應(yīng)的元素锁摔,可以通過模板變量獲取,獲取時可以通過 read 屬性設(shè)置查詢的條件哼审,就是說可以把此視圖轉(zhuǎn)為不同的實例
  • ViewContainerRef :一個視圖容器谐腰,可以在此上面創(chuàng)建、插入涩盾、刪除組件等等
  • ComponentFactoryResolve:一個服務(wù)怔蚌,動態(tài)加載組件的核心,這個服務(wù)可以將一個組件實例呈現(xiàn)到另一個組件視圖上

有了這三個旁赊,一個簡單的思路便連貫了:特定區(qū)域就是一個視圖容器桦踊,可以通過 ViewChild 來實現(xiàn)獲取和查詢,然后使用ComponentFactoryResolve將已聲明未實例化的組件解析成為可以動態(tài)加載的 component终畅,再將此component 呈現(xiàn)到此前的視圖容器中

為了實現(xiàn)此功能籍胯,我寫了一個簡單的例子
我單獨寫了一個特性模塊來測試,下面是結(jié)構(gòu)圖

例子模塊

特性模塊涉及到 lazyload 的知識离福,我也不多講了杖狼。直接看結(jié)構(gòu)說明

  • dy1.component.ts
  • dy2.component.ts

這兩個就是將要動態(tài)加載的組件,內(nèi)容不多妖爷,就是為了測試蝶涩,如圖

dy1.component.ts
dy2.component.ts
  • dynamic.component.ts

這個是此特性模塊對應(yīng)的組件實例,用于聲明一些邏輯動作絮识。簡單看看此組件代碼

dynamic.component.ts

可以看到在頂部導入處必需的三個都在绿聘。在組件類的頂部我通過模板變量的方式獲取了此組件模板視圖上了一個元素來作為視圖容器,可以看看模板的代碼

dynamic.component.ts

紅框處便是我們要在上面動態(tài)加載組件的容器次舌。
看看獲取容器的代碼

dynamic.component.ts

通過模板變量名獲取熄攘,然后 可以通過 read 選項設(shè)置為一個 ViewContainerRef ,最終在生命鉤期 ngAfterViewInit 過后便會獲取此區(qū)域的一個 ViewContainerRef 實例彼念。
看看主要的加載組件函數(shù)

dynamic.component.ts

我們已經(jīng)通過組件類的構(gòu)造函數(shù)注入了ComponentFactoryResolve服務(wù)挪圾,現(xiàn)在便可以調(diào)用其方法來解析得到一個 componentFactory 了浅萧,resolveComponentFactory 解析一個已經(jīng)聲明的組件得到一個可動態(tài)加載的 componentFactory,這里的DY1Component我們已經(jīng)在頂部導入了哲思。然后我們可以直接調(diào)用容器的createComponent函數(shù)將解析出來的componentFactory動態(tài)呈現(xiàn)到容器視圖上洼畅。

然后我們就可以開心的運行、點擊 ”動態(tài)加載組件“ 的按鈕了棚赔。帝簇。
不開心的是,報錯了忆嗜,相信我們可以得到這樣的報錯

error

原來動態(tài)加載的組件必須聲明在特性模塊的 entryComponents 中,下面是angular官網(wǎng)對于entryComponents的說明

Specifies a list of components that should be compiled when this module is defined. For each component listed here, Angular will create a ComponentFactory
and store it in the ComponentFactoryResolver
.

就是說此處聲明的組件 Angular 都會創(chuàng)建一個ComponentFactory并將其存儲在ComponentFactoryResolver中崎岂,也就是動態(tài)加載必需的步驟捆毫。
所以我們將其加到特性模塊 entryComponents

dynamicModule.module.ts

然后我們又可以開心地運行,點擊了冲甘。绩卤。。
然而這次我們又得到另一個錯誤了

error

意思就是DY1Component 還沒有聲明 — — ||| 江醇。 所以還需要將要動態(tài)加載的組件聲明為是此特性模塊的組件濒憋,如圖

dynamicModule.module.ts

然后這次可以開心的看例子了

demo

對于這個方案,上面展示的是最簡單的一面陶夜,沒有考慮到項目的優(yōu)化還有代碼的簡潔凛驮。項目的優(yōu)化問題體現(xiàn)在后期項目的壓縮和預編譯中,如果我們是想要通過組件的名字來動態(tài)加載組件条辟,可能在優(yōu)化有組件的名字都被統(tǒng)一壓縮成一個字母黔夭,所以會導致找不到組件的問題;代碼的簡潔呢因人而異羽嫡,我是喜歡保持根 module 的簡潔本姥,所以有必要另起文件來作為媒介。

說一說改進的方式
新建一個管理類

comMgr.ts

導入動態(tài)加載的組件杭棵,聲明一個供名字獲取組件的變量婚惫,還有一個供根模塊聲明的變量

comMgr.ts

接下來就可以修改之前的引用代碼了:

dynamicModule.module.ts
dynamic.component.ts

可以看到當動態(tài)組件多的時候,根 module還是能保持簡潔魂爪。并且在根組件中可以通過名字獲取對應(yīng)的組件先舷,不怕后期項目優(yōu)化的影響。

(二)動態(tài)創(chuàng)建模塊的方式來加載動態(tài)創(chuàng)建的組件

不同的需求有不同的方案滓侍,對于上面的需求與方案無疑是很適合的密浑,但是需要我們先創(chuàng)建好組件,再聲明到根 module 中粗井,至少缺失了一些靈活性尔破。
現(xiàn)在我又有了另外一個項目場景:我拖動生成了UI 控件街图,只是為了展示對應(yīng)的樣式,UI控件是需要第三方環(huán)境支持的懒构,所以我需要加工拖動的數(shù)據(jù)餐济,拋給后臺處理舟奠,后臺返回包含表示模板议双、組件的字符串的 JSON 數(shù)據(jù)回來,然后我通知另外一個網(wǎng)站卫袒,此網(wǎng)站包含了第三方環(huán)境秩霍,讓他們?nèi)討B(tài)創(chuàng)建這些組件篙悯。一句話概括,就是我要動態(tài)創(chuàng)建不存在的組件而不是已經(jīng)聲明的組件铃绒。
要完成動態(tài)創(chuàng)建組件的鸽照,我們得先看看相關(guān)的api

  • Compiler:用于在運行時運行angular編譯器來創(chuàng)建 ComponentFactory 的服務(wù),然后可以使用它來創(chuàng)建和呈現(xiàn)組件實例

其實最簡單的了解這一個就能實現(xiàn)了颠悬,我們知道 容器創(chuàng)建和呈現(xiàn)組件的函數(shù)需要一個 ComponentFactory矮燎,而Compiler能夠在運行時動態(tài)創(chuàng)建一個ComponentFactory,那就十分符合需求了赔癌。

我新增了一些代碼

dynamic.component.ts
dynamic.component.ts
dynamic.component.ts

這些都是在根組件中的代碼诞外,引入了 Compiler 服務(wù)。新增一個 createModule函數(shù)灾票,通過 ComponentNgModule 修飾器動態(tài)創(chuàng)建新的組件和模塊峡谊,然后調(diào)用 CompilercompileModuleAndAllComponentsSync 方法獲取一個新的ComponentFactory。然后容器的呈現(xiàn)還是一樣刊苍,直接 createComponent靖苇。在模板的按鈕中設(shè)置對應(yīng)的動作后就可以開心的運行和點擊了。班缰。

效果

這次十分順利贤壁,沒有任何報錯。
可能我們會有疑惑埠忘,這個不也還是事先聲明了動態(tài)的組件脾拆。
其實只是我這個例子展示的問題,這里的 模板莹妒、組件類都是可以動態(tài)當成參數(shù)設(shè)置的名船,下面此圖是我在項目中用到的

項目

aot build的問題

使用了這種方案,在項目正常開發(fā)預覽的時候是沒有任何問題的旨怠,但是當我構(gòu)建項目(aot 等)運行的時候渠驼,就會出現(xiàn)下面報錯

error

看錯誤可以知道在項目構(gòu)建后是缺失angular編譯器的,原因就是使用了AOT后已經(jīng)是預編譯了鉴腻,編譯器就會從中移除迷扇。為了解決這一問題百揭,我們可以在這個把 compiler 編譯器在構(gòu)建的時候打到當前的特性包中

dynamic.component.ts
dynamic.component.ts

通過此處代碼就可以將一個angular 編譯器打到當前包中。再次運行build構(gòu)建蜓席,可以看到已經(jīng)沒有之前的錯誤了器一,但是缺因此得到另一個錯誤

error

此錯誤暫時沒能解決,待更新厨内!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祈秕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雏胃,更是在濱河造成了極大的恐慌请毛,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞭亮,死亡現(xiàn)場離奇詭異方仿,居然都是意外死亡,警方通過查閱死者的電腦和手機街州,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門兼丰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玻孟,“玉大人唆缴,你說我怎么就攤上這事∈螋幔” “怎么了面徽?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匣掸。 經(jīng)常有香客問我趟紊,道長,這世上最難降的妖魔是什么碰酝? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任霎匈,我火速辦了婚禮,結(jié)果婚禮上送爸,老公的妹妹穿的比我還像新娘铛嘱。我一直安慰自己,他們只是感情好袭厂,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布墨吓。 她就那樣靜靜地躺著,像睡著了一般纹磺。 火紅的嫁衣襯著肌膚如雪帖烘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天橄杨,我揣著相機與錄音秘症,去河邊找鬼照卦。 笑死,一個胖子當著我的面吹牛历极,可吹牛的內(nèi)容都是我干的窄瘟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼趟卸,長吁一口氣:“原來是場噩夢啊……” “哼蹄葱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锄列,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤图云,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后邻邮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竣况,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年筒严,在試婚紗的時候發(fā)現(xiàn)自己被綠了丹泉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸭蛙,死狀恐怖摹恨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娶视,我是刑警寧澤晒哄,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肪获,受9級特大地震影響寝凌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜孝赫,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一较木、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧青柄,春花似錦伐债、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喇喉,卻和暖如春祖今,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工千诬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留耍目,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓徐绑,卻偏偏與公主長得像邪驮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子傲茄,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這篇文章我們將介紹在 Angular 中如何動態(tài)創(chuàng)建組件毅访。 定義 AlertComponent 組件 首先,我們需...
    semlinker閱讀 1,604評論 0 5
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,823評論 6 342
  • 版本:Angular 5.0.0-alpha AngularDart(本文檔中我們通常簡稱 Angular ) 是...
    soojade閱讀 835評論 0 4
  • 第三章第四章對比第一周第一章第二章的內(nèi)容更有厚度盘榨。有經(jīng)典理論支撐喻粹,有正面例子反面例子,幫助讀者理解草巡。干貨多多守呜!收獲...
    freya_c閱讀 157評論 0 0
  • 北京有很多燒香拜佛的地方,大概是濃厚的古文化和深沉的歷史為這座城市留下的積淀山憨。 作為一個不信佛與道的人查乒,我卻在兩日...
    386035e48425閱讀 640評論 0 3