Angular 模态框组件 | ng-hub-ui-modal
无障碍的 Angular 模态框组件,支持堆叠、全屏模式、模板、键盘处理和 CSS 变量,适用于 standalone 应用。
API 参考
这里是 modal 的完整契约:你可以绑定、监听、投影和设置主题的一切,都集中在一处。接入你需要的部分,自定义你想要的样式——它是 standalone 的,且对 signal 友好。
输入
通过 27 个输入项精细调校 modal。像绑定任意 Angular @Input 一样绑定它们。
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
animation | boolean | — | 若为 true,模态框的打开和关闭将带有动画。默认值:true |
ariaLabelledBy | string | — | 为对话框提供标签的元素 ID,作为 `aria-labelledby` 应用在模态窗口上。 |
ariaDescribedBy | string | — | 描述对话框的元素 ID,作为 `aria-describedby` 应用在模态窗口上。 |
closeAriaLabel | string | 'Close' | 库在自带表头中绘制的关闭按钮的无障碍名称。该按钮没有文本内容,叉号由 CSS 绘制,因此这个字符串就是屏幕阅读器能读出的全部内容:在这里传入翻译后的文本,或在 `HubModalConfig` 上一次性设置默认值。默认值:"Close" |
backdrop | boolean | "static" | — | 若为 true,将创建背景遮罩元素。或者指定 "static" 以创建点击时不关闭模态框的背景遮罩。默认值:true |
beforeDismiss | () => boolean | Promise<boolean> | — | 在模态框被关闭前调用的守卫。返回 `false`、解析为 `false` 的 Promise 或被拒绝的 Promise,对话框就会保持打开。 |
centered | boolean | — | 若为 true,模态框将垂直居中。默认值:false |
closeOnNavigation | boolean | true | 当应用的 URL 改变时关闭对话框,原因为 `ModalDismissReasons.NAVIGATION`。对话框属于打开它的那个页面:若继续留着,它会盖住下一个页面,而它的遮罩会吞掉那里的每一次点击。路径或查询字符串的变化才算;锚点的变化不算,因为它只是在同一个页面内移动读者。对于自行导航且必须保持打开的对话框,设为 `false`。默认 `true`。 |
closeButton | boolean | true | 对话框是否在自己的页眉里绘制关闭按钮。设为 `false` 时不渲染,而不是隐藏:用 CSS 隐藏的按钮仍会被屏幕阅读器念出、仍能被 Tab 键到达,而这正是没有自由出口的对话框所不需要的。它只管这一个按钮,`backdrop: 'static'` 和 `keyboard: false` 是另外两个出口。默认 `true`。 |
placement | HubModalPlacement | — | 控制模态框在视口中的放置位置。默认值:HubModalPlacement.Center |
offcanvas | boolean | false | 把对话框作为抽屉打开:紧贴 `placement` 指定的边缘,该侧不做圆角,拉伸到整个高度(从上下打开时则是宽度),并让主体滚动,使页眉和页脚保持不动。宽度取自 `--hub-modal-offcanvas-width` 而非尺寸刻度——`size: 'lg'` 是 800px,在窄窗口下会盖住抽屉本该并排阅读的那份文档。不传 `placement` 时从末端边缘打开。 |
container | string | HTMLElement | — | 模态窗口挂载到的 CSS 选择器或元素。默认值:`body` |
fullscreen | boolean | "sm" | "md" | "lg" | "xl" | "xxl" | string | — | `true` 让对话框在任何宽度下都全屏;`"md"` 这样的断点名称则只在小于该宽度时全屏。其他字符串会应用 `modal-fullscreen-<值>-down`。默认值:false |
injector | Injector | — | 用于解析内容组件依赖的 Injector。 |
keyboard | boolean | — | 若为 true,按下 Escape 键时模态框将关闭。默认值:true |
scrollable | boolean | — | 固定对话框并让其主体滚动,而不是让对话框超出视口。默认值:false |
size | "sm" | "lg" | "xl" | string | — | 模态框窗口的尺寸 |
variant | "primary" | "success" | "danger" | "warning" | "info" | string | — | 对话框的语义强调色,用在真正有含义的对话框上:破坏性确认、成功提示。它重新指定唯一的 `--hub-modal-accent` 槽位,emphasis / subtle / on / border 这几个角色都在对话框自身上由它派生,所以一个值就能同时改变带色的背景、外框以及页眉页脚的分隔线,还有标题。样式表内置九个:`primary`、`secondary`、`success`、`danger`、`warning`、`info`、`neutral`、`light`、`dark`。其他任意字符串也接受,会给窗口加上 `hub-modal--<名称>`:自定义强调色只需要在全局样式表里写一条规则,无需重新构建。顶部色条也属于这一套,但出厂宽度为零:在对话框上设置 `--hub-modal-accent-bar-width` 即可开启。不指定 variant 时对话框保持中性。 |
windowClass | string | — | 附加到模态框窗口的自定义类 |
modalDialogClass | string | — | 追加到 `hub-modal__dialog` 元素上的自定义类 |
backdropClass | string | — | 附加到模态框背景遮罩的自定义类 |
dismissSelector | string | — | 可触发模态框窗口关闭(dismiss)的元素的自定义选择器。默认值:"[data-dismiss=\"modal\"]" |
closeSelector | string | — | 可触发模态框窗口关闭(close)的元素的自定义选择器。默认值:"[data-close=\"modal\"]" |
headerSelector | string | — | 模态框窗口头部元素的自定义选择器 |
footerSelector | string | — | 模态框窗口底部元素的自定义选择器 |
bodySelector | string | — | 其子节点构成主体的区块的 CSS 选择器。不指定时,主体是表头和表尾剩下的部分,取决于内容的书写顺序;指定后主体被有意放置,任何插槽都未认领的内容仍会跟在它后面。 |
data | D | — | 打开模态框窗口时需要传递的额外数据 |
输出
响应 modal 的行为——有 1 个事件可供你挂接逻辑。
| 名称 | 类型 | 描述 |
|---|---|---|
dismiss | any | 当用户关闭(dismiss)模态框时由模态框窗口发出,例如按下 Escape、点击背景遮罩或激活内置关闭按钮。载荷为 dismiss 原因(ModalDismissReasons.ESC、ModalDismissReasons.BACKDROP_CLICK 或自定义值)。 |
方法
通过代码驱动 modal——其编程接口提供 17 个方法。
| 名称 | 签名 | 返回值 | 描述 |
|---|---|---|---|
HubModal.open | open<C, R, D>(content: Type<C> | TemplateRef<any> | string, options?: HubModalOptions<D>): HubModalRef<C, R> | HubModalRef<C, R> | 使用给定内容(组件类型、TemplateRef 或字符串)和选项打开一个新的模态框窗口,并返回用于控制它的 HubModalRef。内容组件可以注入 HubActiveModal 和 HUB_MODAL_DATA 令牌,以便与模态框交互并读取数据载荷。 |
HubModal.dismissAll | dismissAll(reason?: any): void | — | 以所提供的原因关闭(dismiss)当前显示的所有模态框窗口。 |
HubModal.hasOpenModals | hasOpenModals(): boolean | boolean | 指示应用中当前是否存在任何打开的模态框窗口。 |
HubModal.activeInstances | activeInstances: EventEmitter<HubModalRef[]> | EventEmitter<HubModalRef[]> | 事件发射器,每当有模态框被打开或移除时,发出当前打开的 HubModalRef 实例列表。 |
HubModalRef.close | close(result?: R): void | — | 以可选的结果值关闭模态框。HubModalRef.result Promise 会以所提供的值 resolve。 |
HubModalRef.dismiss | dismiss(reason?: any): void | — | 以可选的原因值关闭(dismiss)模态框。HubModalRef.result Promise 会以所提供的值 reject。若配置了 beforeDismiss 守卫,则会予以遵循。 |
HubModalRef.update | update(options: HubModalUpdatableOptions): void | — | 更新已打开模态框的选项(aria 属性、centered、placement、fullscreen、backdropClass、size、variant、windowClass、modalDialogClass)。 |
HubModalRef.componentInstance | componentInstance: C | void | C | void | 用作模态框内容的组件实例。当内容为 TemplateRef 或模态框已关闭时返回 undefined。 |
HubModalRef.result | result: Promise<R> | Promise<R> | 一个 Promise:模态框关闭时以关闭结果 resolve,被关闭(dismiss)时以 dismiss 原因 reject。 |
HubModalRef.closed | closed: Observable<R> | Observable<R> | Observable,当模态框关闭时发出传给 close() 的结果。 |
HubModalRef.dismissed | dismissed: Observable<any> | Observable<any> | Observable,当模态框被关闭(dismiss)时发出 dismiss 原因——即传给 dismiss() 的值,或诸如点击背景遮罩、按下 Escape 之类的内部原因。 |
HubModalRef.shown | shown: Observable<void> | Observable<void> | Observable,在模态框完全可见且打开动画结束后发出并完成。 |
HubModalRef.hidden | hidden: Observable<void> | Observable<void> | Observable,在模态框窗口和背景遮罩均已隐藏、动画结束且其元素已从 DOM 中移除后发出并完成。 |
HubActiveModal.close | close(result?: R): void | — | 关闭承载该内容组件的模态框,并以可选的结果值 resolve HubModalRef.result Promise。 |
HubActiveModal.dismiss | dismiss(reason?: any): void | — | 关闭(dismiss)承载该内容组件的模态框,并以可选的原因值 reject HubModalRef.result Promise。 |
HubActiveModal.update | update(options: HubModalUpdatableOptions): void | — | 从内容组件内部更新已打开模态框的选项。 |
HubActiveModal.data | data: D | D | 通过 HubModalOptions.data 传入的类型化载荷。等同于注入 HUB_MODAL_DATA 令牌;未提供 data 选项时解析为 null。 |
模板
打造你自己的样式——1 个模板插槽让你可以投影自定义标记。
| 名称 | 描述 | 示例 |
|---|---|---|
Modal Template | 可传给模态服务的模板引用。只有在 `open()` 时给出 `headerSelector`、`bodySelector` 和 `footerSelector`,表头、主体和表尾区块才会成为插槽;否则整个模板都会落进主体。 | <ng-template #modalTemplate let-close="close" let-dismiss="dismiss">
<div hubModalHeader>
<h4 class="hub-modal__title">Modal Title</h4>
</div>
<div hubModalBody>
Modal content goes here
</div>
<div hubModalFooter>
<button hubButton color="secondary" (click)="dismiss()">Cancel</button>
<button hubButton color="primary" (click)="close('result')">OK</button>
</div>
</ng-template>
<!-- The three blocks become slots only when the selectors are given:
this.modal.open(this.modalTemplate, {
headerSelector: '[hubModalHeader]',
bodySelector: '[hubModalBody]',
footerSelector: '[hubModalFooter]'
});
Without them the whole template lands in hub-modal__body. --> |