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+ 高级教程 – 目录

 

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