當前位置:
首頁 > 知識 > 從源碼看 angular/material2 中 dialog模塊的實現

從源碼看 angular/material2 中 dialog模塊的實現

本文將探討material2中popup彈窗即其Dialog模塊的實現。

使用方法

1.引入彈窗模塊

2.自己準備作為模板的彈窗內容組件

3.在需要使用的組件內注入 MatDialog 服務

4.調用 open 方法創建彈窗,並支持傳入配置、數據,以及對關閉事件的訂閱

深入源碼

進入material2的源碼,先從 MatDialog 的代碼入手,找到這個 open 方法:

從源碼看 angular/material2 中 dialog模塊的實現

從源碼看 angular/material2 中 dialog模塊的實現

總體看來彈窗的發起分為三部曲:

1.創建一個彈出層(其實是一個原生DOM,起宿主和入口的作用)

2.在彈出層上創建彈窗容器組件(負責提供遮罩和彈齣動畫)

3.在彈窗容器中創建傳入的彈窗內容組件(負責提供內容)

彈出層的創建

對於其他組件,僅僅封裝模板以及內部實現就足夠了,最多還要增加與父組件的數據、事件交互,所有這些事情,單使用angular
Component就足夠實現了,在何處使用就將組件選擇器放到哪裡去完事。

但對於彈窗組件,事先並不知道會在何處使用,因此不適合實現為一個組件後通過選擇器安放到頁面的某處,而應該將其作為彈窗插座放置到全局,並通過服務來調用。

material2也要面臨這個問題,這個彈窗插座是避免不了的,那就在內部實現它,在實際調用彈窗方法時動態創建這個插座就可以了。要實現效果是:對用戶來說只是在單純調用一個
open 方法,由material2內部來創建一個彈出層,並在這個彈出層上創建彈窗。

找到彈出層的創建代碼如下:

從源碼看 angular/material2 中 dialog模塊的實現

其中最關鍵的方法其實是 getContainerElement() ,
material2把最"丑"最不angular的操作放在了這裡面,看看其實現:

從源碼看 angular/material2 中 dialog模塊的實現

彈窗容器的創建

跳過其他細節,現在得到了一個彈出層引用
overlayRef。material2接下來給它添加了一個彈窗容器組件,這個組件是material2自己寫的一個angular組件,打開彈窗時的遮罩部分以及彈窗的外輪廓其實就是這個組件,對於為何要再套這麼一層容器,有其一些考慮。

1.動畫效果的保護

這樣動態創建的組件有一個缺點,那就是其銷毀是無法觸發angular動畫的,因為一瞬間就銷毀掉了,所以material2為了實現動畫效果,多加了這麼一個容器來實現動畫,在關閉彈窗時,實際上是在播放彈窗的關閉動畫,然後監聽容器的動畫狀態事件,在完成關閉動畫後才執行銷毀彈窗的一系列代碼,這個過程與其為難用戶來實現,不如自己給封裝了。

2.注入服務的保護

目前版本的angular關於在動態創建的組件中注入服務還存在一個注意點,就是直接創建出的組件無法使用隱式的依賴注入,也就是說,直接在組件的
constructor 中聲明服務對象的實例是不起作用的,而必須先注入 Injector ,再使用這個 Injector 把注入的服務都 get 出來:

從源碼看 angular/material2 中 dialog模塊的實現

解決的辦法是不直接創建出組件來注入服務,而是先創建一個指令,再在這個指令中創建組件並注入服務使用,這時隱式的依賴注入就又有效了,material2就是這麼乾的:

其中的 cdkPortalHost 指令就是用來後續創建組件的。

所以創建這麼一個彈窗容器組件,用戶就感覺不到這一點,很順利的像普通組件一樣注入服務並使用。

創建彈窗容器的核心方法在 dom-portal-host.ts 中:

從源碼看 angular/material2 中 dialog模塊的實現

所做的事情無非就是動態創建組件的四步曲:

1.創建工廠

2.使用工廠創建組件

3.將組件整合進AppRef(同時設置一個移除的方法)

4.在DOM中插入這個組件的原始節點

彈窗內容

從上文可以知道,得到的彈窗容器組件中存在一個宿主指令,實際上是在這個宿主指令中創建彈窗內容組件。進入宿主指令的代碼可以找到
attachComponentPortal 方法:

從源碼看 angular/material2 中 dialog模塊的實現

最後這一步就非常明了了,正是官方文檔中使用的動態創建組件的方式(ViewContainerRef),至此彈窗已經成功彈出到界面中了。

彈窗的關閉

還有最後一個要注意的點就是彈窗如何關閉,從上文可以知道應該要先執行關閉動畫,然後才能銷毀彈窗,material2的彈窗容器組件添加了一堆節點:

從源碼看 angular/material2 中 dialog模塊的實現

其中需要關注的就是material2在容器組件中添加了一個動畫叫 slideDialog ,並為其設置了動畫事件,現在關注動畫完成事件的回調:

從源碼看 angular/material2 中 dialog模塊的實現

這裡發射了這個事件,並在 MatDialogRef 中訂閱:

從源碼看 angular/material2 中 dialog模塊的實現

從源碼看 angular/material2 中 dialog模塊的實現

總結

以上就是整個material2 dialog能力走通的過程,可見即使是 angular 這麼完善又龐大的框架,想要完美解耦封裝彈窗能力也不能完全避免原生DOM操作。

(轉自博客園)



2017中公教育特別推出勤工儉學計劃:http://www.ujiuye.com/zt/qgjx/?wt.bd=bgz

還有500萬的就業基金等著你:http://www.ujiuye.com/zt/jycj/?wt.bd=bgz

海量IT課程學習就在優學網:http://xue.ujiuye.com/

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT優就業 的精彩文章:

Zeppelin源碼
收藏|高效實用的.NET開源項目
「js高手之路」打造通用的勻速運動框架

TAG:IT優就業 |