Modal 模态框
Modal 在变暗的页面上弹出一个对话框:桌面端是居中的卡片,手机上是底部弹出的面板(bottom sheet),两者是同一个组件。它同时覆盖卡片和对话框两种用法:title、正文、footer 和确认 / 取消按钮;也可以用 raw 自己画外观。
它和 Popover 一样是浮层,而不是原生 <dialog>:它通过 z-index 管理器叠放,所以在里面打开的 Select、Popover、Tooltip 会显示在它上面,按 Esc 先关最里层。打开期间焦点留在里面,背后的页面对读屏软件隐藏、也不能滚动;关闭后焦点回到打开它的元素。
演示
基础用法
用 show 和 onUpdateShow 控制。打开时焦点落在正文的第一个输入框;按 Esc、点遮罩、点 ×、取消和保存都会关闭。
异步确认和阻止关闭
onPositiveClick 返回 Promise 时,按钮会显示加载,直到它结束。返回 false(或 resolve 成 false 的 Promise)则不关闭;onClose 对 × 也一样。
必须做出选择
maskClosable={false}、closeOnEsc={false} 和 closable={false} 之后只能点按钮关闭。onMaskClick 和 onEsc 仍会报告这些尝试。
长内容
标题和按钮固定不动,正文在两者之间滚动。footer 在按钮上方加一行。
对话框和底部面板
presentation="auto"(默认)在宽屏是对话框,窗口窄于 640px(Grid 的 s 断点)时变成底部面板;dialog 和 sheet 固定其中一种。底部面板占满屏宽、从下方滑入、避开 iPhone 底部的横条,按钮等宽排开。整个应用的默认值可以用 ConfigProvider 的 componentOptions={{ Modal: { presentation: "dialog" } }} 设置。
自定义外观
raw 去掉背景、标题行和 ×,只保留遮罩、位置、动画和焦点管理。请用 aria-label 或 aria-labelledby 给对话框起名。
内部的浮层
模态框里的 Select 会显示在它上面;从模态框里再打开一个模态框会叠在最上层,按 Esc 或点它的遮罩只关闭最上面那个。
Props
| 名称 | 类型 | 默认值 | 说明 | 版本 |
|---|---|---|---|---|
show | boolean | undefined | 受控的显示状态。 | 未发布 |
defaultShow | boolean | false | 非受控时的初始显示状态。 | 未发布 |
onUpdateShow | (show: boolean) => void | undefined | 模态框要打开或关闭时,以新的显示状态调用。 | 未发布 |
title | ReactNode | undefined | 标题,同时作为对话框的名称。 | 未发布 |
children | ReactNode | undefined | 正文。纯文本时也作为对话框的描述(aria-describedby)。 | 未发布 |
footer | ReactNode | undefined | 正文下方、按钮上方的一行。 | 未发布 |
action | ReactNode | undefined | 替换确认 / 取消按钮。 | 未发布 |
positiveText | ReactNode | undefined | 主按钮文字;设置了才显示。 | 未发布 |
negativeText | ReactNode | undefined | 次按钮文字;设置了才显示。 | 未发布 |
positiveButtonProps | Partial<ButtonProps> | undefined | 主按钮的额外属性,比如 type: "error"。 | 未发布 |
negativeButtonProps | Partial<ButtonProps> | undefined | 次按钮的额外属性。 | 未发布 |
onPositiveClick | (event: MouseEvent) => boolean | void | Promise<boolean | void> | undefined | 点主按钮时调用。返回 false 不关闭;返回 Promise 时显示加载。 | 未发布 |
onNegativeClick | (event: MouseEvent) => boolean | void | Promise<boolean | void> | undefined | 点次按钮时调用。返回 false 不关闭。 | 未发布 |
closable | boolean | true | 是否显示 × 按钮。 | 未发布 |
onClose | () => boolean | void | Promise<boolean | void> | undefined | 点 × 时调用。返回 false 不关闭。 | 未发布 |
raw | boolean | false | 去掉背景、标题行和 ×,自己画外观。 | 未发布 |
presentation | 'dialog' | 'sheet' | 'auto' | 'auto' | 对话框、底部面板,或窄于 640px 时变成底部面板的对话框。 | 未发布 |
maskClosable | boolean | true | 点遮罩是否关闭。 | 未发布 |
onMaskClick | (event: MouseEvent) => void | undefined | 点遮罩时调用,不论是否关闭。 | 未发布 |
closeOnEsc | boolean | true | 按 Esc 是否关闭。 | 未发布 |
onEsc | () => void | undefined | 按 Esc 时调用,不论是否关闭。 | 未发布 |
autoFocus | boolean | true | 打开时聚焦正文里第一个可聚焦元素(其次是按钮,最后是 ×);关闭此项则聚焦对话框本身。 | 未发布 |
trapFocus | boolean | true | 把 Tab 限制在里面,并对读屏软件隐藏页面(aria-modal)。 | 未发布 |
blockScroll | boolean | true | 打开期间禁止页面滚动。 | 未发布 |
displayDirective | 'if' | 'show' | 'if' | 关闭后卸载,还是保留 DOM 并隐藏。 | 未发布 |
transformOrigin | 'mouse' | 'center' | 'mouse' | 从打开它的那次点击处展开,还是从自身中心展开。 | 未发布 |
to | string | HTMLElement | false | undefined | 挂载位置;false 表示就地渲染。默认是 ConfigProvider 的 portalContainer,其次是 document.body。 | 未发布 |
zIndex | number | undefined | 固定的 z-index,不再按打开顺序叠在之前的浮层上面。 | 未发布 |
onAfterEnter | () => void | undefined | 进入动画结束时调用。 | 未发布 |
onAfterLeave | () => void | undefined | 离开动画结束时调用。 | 未发布 |
其余属性以及 className、style、ref 都传给对话框元素(role="dialog");宽度用 style 设置,底部面板仍会撑满屏宽。开启「减少动态效果」时,对话框和底部面板只做淡入淡出。