Angular Material 17+ 高級教程 – Overlay

Overlay, Dialog, Modal, Popover 傻傻分不清楚

參考:

Medium – Modal?Dialog?你真的知道他們是什麼嗎?

Popups, dialogs, tooltips, and popovers— UX Patterns #2

掘金 – 對話框、模態框和彈出框看起來很相似,它們有何不同?

傻傻分不清楚是正常的,因爲市場上並沒有統一的規範。

我個人的理解是這樣:

  1. Overlay

    Overlay 的意思是覆蓋,但凡有一個東西覆蓋在另一個東西之上,都可以抽象理解爲 Overlay。

    用於 HTML 的話,只要是 position 定位覆蓋在 body / 任何 element 之上,都是 Overlay。

  2. Dialog 

    Material Design 對 Dialog 有明確的定義,Dialog 是一個覆蓋在 body 之上的 Overlay,它會強制要求用戶與之交互,不然 Dialog 就會一直遮擋在 body 之上。

  3. Modal

    HTML 對 Dialog 的定義和 Material Design 不同,HTMLDialogElement 有 2 個顯示方法,一個是 show 一個是 showModal。

    show 只是普通的顯示在 body 裏,showModal 纔是像 Material Dialog 那樣以 Overlay 形式顯示。

    所以對我來說 HTML Modal 和 Material Dialog 是一樣的東西,但 HTML Dialog 和 Material Dialog 則是不同的。

  4. Popover

    Popover 也是一種 Overlay,但是它不像 Dialog 那樣搶眼,也不那麼強制交互。

    Dialog 通常顯示在屏幕的正中間大大個,Popover 則出現在 trigger 它的 element 附近小小個。

    Dialog 通常會有一層全屏的黑影 (backdrop) 遮擋住後面 body 的內容,而 Popover 通常是沒有 backdrop 的。

除了 Dialog,Modal,Popover 以外,其實還有很多的 Overlay,比如說 Snackbar。

但無論如何,本篇主講是 Overlay,所以我們也不需要分的太清楚先,反正大家都是 Overlay 嘛。

 

CDK Overlay

CDK Overlay 是 Angular Material 封裝的底層功能,用來實現抽象的 Overlay,而具體的 Material Dialog, Menu, Snarbar, Tooltip 等等等都是基於 CDK Overlay 實現的。

我們可以把 CDK Overlay 分成 5 個部分來學習

  1. Overlay Dependency Injection Provider

    它是一個 Root Level Provider 用來創建 OverlayRef

  2. OverlayRef

    OverlayRef 是一個普通的 class。

    Overlay 和 OverlayRef 的關係類似於 FocusTrapFactory 和 FocusTrap 的關係。

    我們可以創建多個 Overlay (遮罩層),每一個對應一個 OverlayRef 對象。

  3. PositionStrategy

    PositionStrategy 用來控制 Overlay 內容顯示的位置,比如說 Dialog 內容通常是顯示在屏幕的中心。

    Popover 通常顯示在 trigger 的附近。

  4. ScrollStrategy
    當 Overlay 顯示以後,body scroll 會怎麼樣?
    比如說:
    a. close Overlay when body scroll
    b. block body scroll
    等等
  5. Overlay 指令

    如同 CdkTrapFocus 指令那樣,Overlay 也有類似的指令,它們的目的就只是爲了方便開發。

    底層依然是 Overlay Provider 和 OverlayRef。

好,接下來我們就一個一個部分學習唄🚀

 

Overlay Provider

Overlay 是一個 Root Level Provider,我們用它來創建遮罩層。

export class AppComponent {
  constructor() {
    // 1. inject Overlay
    const overlay = inject(Overlay);

    afterNextRender(() => {
      // 2. 創建遮罩層
      const overlayRef = overlay.create();
    });
  }
}

調用 Overlay.create 會創建一個遮罩層,然後它會返回一個 OverlayRef,我們可以通過這個 OverlayRef 對遮罩層做後續的改動。

注:Overlay.create 是可以傳入各種配置的,不過這些配置之後也可以透過 OverlayRef 做設置或修改,所以我把它放到 OverlayRef 的部分一起教,我們先關注 Overlay.create 就好了。

遮罩層的 HTML 結構

遮罩層會被 append 到 body 裏 (app-root sibling)。

Overlay Container (.cdk-overlay-container) 是一個 position fixed div

Overlay Pane (cdk-overlay-pane) 是一個 position absolute div

我們再創建一個遮罩層看看 (是的,遮罩層是可以創建多個的)

afterNextRender(() => {
  // 2. 創建遮罩層
  const overlayRef1 = overlay.create();
  const overlayRef2 = overlay.create();
});

HTML 結構

Overlay Container 依然只有一個,Overlay Host 和 Pane 則多了一個,後一個創建的遮罩層會在下方,所以它會在比較上層,雖然所有遮罩層 z-index 都是 1000。

此時,雖然遮罩層已經出現了,但它只是兩個定了位的空 div,用戶啥也看不見。這是因爲創建完整的遮罩層需要 2 個步驟,第一個是 Overlay.create,第二個是 OverlayRef.attach (下一 part 會教)。

我們先逛一下 Overlay.create 的源碼,它在 overlay.ts

沒什麼特別的,就只是創建了 3 個 div 而已 -- Overlay Container,Overlay Host,Overlay Pane。

 

OverlayRef & OverlayConfig

上一 part 我們留了兩個點沒有解釋清楚:

  1. OverlayConfig

    在 Overlay.create 時我們可以傳入一個配置 -- OverlayConfig

    這個 OverlayConfig 在整個 create 環節裏並沒有被使用到,它只是轉給了 OverlayRef 而已。

    OverlayRef 纔是真正消費 OverlayConfig 的人。

  2.  

    要創建一個完整的遮罩層需要兩個步驟,第一步 Overlay.create 我們已經做了,第二部是 OverlayRef.attach。

    attach 環節就會使用到 OverlayConfig 了,雖然有一些 config 在 attach 之後依然可以修改,但有一些是不行的,所以我們要搞清楚 config 和環節的關係。

OverlayRef.attach

上一 part 有提到,Overlay.create 只是創建了幾個空的 div,其中一個 div 是 Overlay Pane,它是一個 DomPortalOutlet (不熟悉 Portal 的朋友請看這篇 CDK Portal)。

我們想呈現的具體內容需要透過 ComponentPortal / TemplatePortal / DomPortal 的方式 attach 給 Overlay Pane DomPortalOutlet 才能被呈現出來。

這個 attach 過程便是透過 OverlayRef.attach 方法來完成的。

const overlayRef = overlay.create();
// 1. 創建 Portal (ComponentPortal, TemplatePortal, DomPortal 都可以)
const helloWorldPortal = new ComponentPortal(HelloWorldComponent);
// 2. 把 Portal attach 到 Overlay Pane
overlayRef.attach(helloWorldPortal);

效果

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

目錄

上一篇 Angular Material 17+ 高級教程 – CDK Accessibility の ListKeyManager

下一篇 TODO

想查看目錄,請移步 Angular 17+ 高級教程 – 目錄

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章