u
This commit is contained in:
1 parent
e99a9fb274
commit
0be0b0767a
788 files changed
+112023
-14941
No files matched your search
@@ -0,0 +1,175 @@
|
||||
---
|
||||
title: Modal 对话框
|
||||
description: 模态窗口,支持拖动、缩放、全屏与命令式确认框
|
||||
---
|
||||
|
||||
# Modal 对话框
|
||||
|
||||
`Modal` 在当前页面上方打开一个模态窗口,用户必须先处理它才能继续。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 需要用户**聚焦处理**一件事:填写表单、确认危险操作、查看详情;
|
||||
- 需要打断当前流程、且不该被忽略时(用 `maskClosable=false`、`keyboard=false`、`closable=false` 收紧关闭入口);
|
||||
- 只是提示结果、不需要用户操作时,用 [Message](/ui/feedback/message) 更轻;
|
||||
- 内容很长、或需要保留页面上下文时,可以考虑 [Drawer](/ui/overlay/drawer)。
|
||||
|
||||
## 基础用法
|
||||
|
||||
`v-model:open` 控制显隐。三个事件区分关闭来源:`confirm`(底部确认按钮)、`cancel`(取消按钮 / 遮罩 / Esc / 右上角关闭)、`closed`(退场动画结束)。
|
||||
|
||||
<demo vue="modal/basic.vue" />
|
||||
|
||||
## 拖动、缩放与全屏
|
||||
|
||||
默认允许拖动标题栏移动面板、拖拽四边缩放、右上角切换全屏。三者互相协调:进入全屏会复位拖拽位置并禁用缩放手柄。
|
||||
|
||||
<demo vue="modal/resize.vue" />
|
||||
|
||||
## 居中显示
|
||||
|
||||
面板默认贴顶(`align-items: flex-start`)——这样长内容不会把标题栏顶出视口。确认类、短表单可以开 `centered` 垂直居中。
|
||||
|
||||
<demo vue="modal/resize.vue" />
|
||||
|
||||
## 控制关闭入口
|
||||
|
||||
`maskClosable` / `keyboard` / `closable` / `footer` 分别控制遮罩点击、Esc、右上角关闭按钮与底部按钮区。
|
||||
|
||||
<demo vue="modal/mask.vue" />
|
||||
|
||||
## 表单弹窗与异步确认
|
||||
|
||||
`confirmLoading` 期间**阻止一切关闭**(含遮罩、Esc、取消按钮),避免异步提交被打断;底部按钮自动进入加载态。
|
||||
|
||||
<demo vue="modal/form.vue" />
|
||||
|
||||
## 命令式确认框
|
||||
|
||||
```ts
|
||||
const handle = G3Modal.confirm({
|
||||
title: '确定删除?',
|
||||
content: '删除后不可恢复',
|
||||
confirmText: '删除',
|
||||
confirmButtonProps: { danger: true },
|
||||
onConfirm: async () => {
|
||||
await api.remove() // 返回 Promise 时按钮 loading
|
||||
},
|
||||
onCancel: () => {},
|
||||
})
|
||||
|
||||
handle.destroy() // 立即关闭并卸载(不等退场动画)
|
||||
```
|
||||
|
||||
<demo vue="modal/confirm.vue" />
|
||||
|
||||
**`onConfirm` 的 Promise 语义**:resolve → 关闭;reject → 保持打开、解除 loading,错误由调用方提示。
|
||||
|
||||
**`onCancel` 的触发范围**:只有点击「取消」按钮才会调用 `onCancel`;点遮罩空白、Esc、右上角关闭按钮都是**静默关闭**(只关窗,不跑取消逻辑),避免用户随手点空白就触发取消副作用。
|
||||
|
||||
<demo vue="modal/confirm-async.vue" />
|
||||
|
||||
## 自定义底部与头部
|
||||
|
||||
`#footer` 完全接管底部;`#header-extra` 放标题右侧的额外动作。
|
||||
|
||||
<demo vue="modal/footer-slot.vue" />
|
||||
|
||||
## API
|
||||
|
||||
### Props(Modal)
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `open` | `boolean` | — | 受控打开状态;不传即非受控 |
|
||||
| `defaultOpen` | `boolean` | `false` | 非受控时的初始状态 |
|
||||
| `title` | `string` | `''` | 标题 |
|
||||
| `width` | `number \| string` | `520` | 面板宽度。数字按 px,`'60%'` 之类的字符串原样使用 |
|
||||
| `centered` | `boolean` | `false` | 垂直居中(默认贴顶,长内容不会把标题顶出视口) |
|
||||
| `mask` | `boolean` | `true` | 是否显示遮罩 |
|
||||
| `maskClosable` | `boolean` | `true` | 点击遮罩空白关闭 |
|
||||
| `keyboard` | `boolean` | `true` | Esc 关闭 |
|
||||
| `closable` | `boolean` | `true` | 显示右上角关闭按钮 |
|
||||
| `fullscreen` | `boolean` | `true` | 显示右上角全屏切换按钮 |
|
||||
| `resizable` | `boolean` | `true` | 允许拖拽四边缩放宽高 |
|
||||
| `footer` | `boolean` | `true` | 显示底部按钮区(取消 + 确认) |
|
||||
| `confirmText` | `string` | 语言包 `common.confirm` | 确认按钮文字 |
|
||||
| `cancelText` | `string` | 语言包 `common.cancel` | 取消按钮文字 |
|
||||
| `confirmLoading` | `boolean` | `false` | 确认中:按钮 loading,并**阻止一切关闭操作** |
|
||||
| `popupContainer` | `PopupContainer` | ConfigProvider 配置 | 挂载容器,默认 `body` |
|
||||
|
||||
### Events(Modal)
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `update:open` | `(open: boolean)` | 打开状态变化 |
|
||||
| `confirm` | `()` | 点击底部确认按钮(不自动关闭,由你决定何时关) |
|
||||
| `cancel` | `()` | 取消按钮 / 遮罩 / Esc / 右上角关闭被触发 |
|
||||
| `closed` | `()` | 退场动画结束、DOM 已销毁(此时滚动锁已释放、焦点已归还) |
|
||||
|
||||
### Slots(Modal)
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `default` | — | 正文 |
|
||||
| `header-extra` | — | 标题右侧的自定义动作(在全屏/关闭按钮之前) |
|
||||
| `footer` | — | 自定义底部;不传时渲染「取消 + 确认」 |
|
||||
|
||||
### G3Modal.confirm 参数
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `title` | `string` | `''` | 标题 |
|
||||
| `content` | `string` | `''` | 正文纯文本 |
|
||||
| `confirmText` | `string` | 语言包 | 确认按钮文字 |
|
||||
| `cancelText` | `string` | 语言包 | 取消按钮文字 |
|
||||
| `confirmButtonProps` | `Partial<ButtonProps> & { danger?: boolean }` | `{}` | 透传给确认按钮;`danger: true` 等价于 `type: 'danger'` |
|
||||
| `onConfirm` | `() => void \| Promise<unknown>` | — | 确认回调,返回 Promise 时按钮 loading |
|
||||
| `onCancel` | `() => void` | — | 取消回调(**仅**点击取消按钮触发) |
|
||||
|
||||
**返回值**:`{ destroy: () => void }`。
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
export interface ModalProps {
|
||||
open?: boolean
|
||||
defaultOpen?: boolean
|
||||
title?: string
|
||||
width?: number | string
|
||||
centered?: boolean
|
||||
mask?: boolean
|
||||
maskClosable?: boolean
|
||||
keyboard?: boolean
|
||||
closable?: boolean
|
||||
fullscreen?: boolean
|
||||
resizable?: boolean
|
||||
footer?: boolean
|
||||
confirmText?: string
|
||||
cancelText?: string
|
||||
confirmLoading?: boolean
|
||||
popupContainer?: PopupContainer
|
||||
}
|
||||
|
||||
export interface ModalConfirmOptions {
|
||||
title?: string
|
||||
content?: string
|
||||
confirmText?: string
|
||||
cancelText?: string
|
||||
confirmButtonProps?: Partial<ButtonProps> & { danger?: boolean }
|
||||
onConfirm?: () => void | Promise<unknown>
|
||||
onCancel?: () => void
|
||||
}
|
||||
|
||||
export interface ModalConfirmHandle {
|
||||
destroy: () => void
|
||||
}
|
||||
```
|
||||
|
||||
## 实现说明
|
||||
|
||||
- **遮罩点击判定**:只响应「点击事件的目标就是外层容器」且「mousedown 不在面板内」的情况。后者是为了防拖选文本:在输入框里按下鼠标、拖到遮罩上松开时,`click.target` 会回溯成共同的祖先容器,如果只看 click 就会误判成「点了遮罩要关闭」;
|
||||
- **焦点与滚动**:打开时记录当前焦点、锁 body 滚动、把焦点移进面板,并用 Tab 循环把焦点约束在面板内;关闭时**等退场动画结束**才解锁滚动、复位尺寸、把焦点还给触发元素——否则动画还在播的时候背景就能滚动、焦点提前跳走,屏幕阅读器会跟丢;
|
||||
- **滚动锁是引用计数**:Modal 里再开 Drawer、或弹窗里开下拉,不会互相提前解锁;
|
||||
- **命令式挂载**:`G3Modal.confirm()` 自建容器挂到 `body`,`open` 初始即为 `true`,因此内部对 `isOpen` 用了 `immediate: true` 的 watch、并给 `Transition` 加了 `appear`,让「挂载」与「受控打开」走同一段初始化逻辑,退场动画结束后再卸载容器;
|
||||
- **层级**:打开时从 z-index 注册表取 `modal` 档,闭包回收;浮层类(下拉、日期面板)取 `popup` 档,所以弹窗里的浮层一定盖在弹窗上。
|
||||
Reference in new issue
Block a user