Modal 对话框
模态对话框,用于需要用户确认或输入的中断场景。
基础用法
基础用法
这是一个基础对话框示例。
受控显示
visible 为受控属性:由宿主(按钮 / JS)设置或移除,组件不会自动恢复;关闭后可监听 oas-ok / oas-cancel 后移除 visible。
受控显示(visible)
外部按钮直接设置 / 移除 visible 控制显隐,无需依赖底部按钮。
受控 / 非受控契约:组件自身是非受控 + 事件通知模型——用户关闭路径(遮罩 / ✕ / Esc / 取消)由组件自行移除 visible 并派发 oas-close(detail.source / detail.action 标明来源与动作),宿主上的 visible attribute 始终与真实状态同步、不会残留。声明式绑定场景(visible 由宿主 state 驱动)应在 oas-close 中把 state 置为关闭,避免关闭后 state 又把 visible 写回;若监听 oas-before-close 并 preventDefault(),则组件保持打开、visible 不动。
无底部按钮
无底部按钮
隐藏底部操作区,仅通过 ✕ / Esc / 遮罩关闭。
禁止遮罩关闭
禁止遮罩关闭
点击遮罩不会关闭,需通过按钮或 Esc 关闭。
自定义宽度
自定义宽度
通过 width 指定对话框宽度,支持像素或百分比(如 50%),未设置时默认 520px。
垂直居中
垂直居中
默认对话框靠上偏移(顶部 100px),添加 centered 后垂直居中显示。
可拖拽
可拖拽
按住标题栏可拖动对话框;Esc、遮罩关闭与焦点行为保持不变。
全屏对话框
fullscreen 让对话框铺满视口(无圆角、无外边距)。优先级定义:fullscreen 胜于 width / centered / draggable——width 被忽略、centered 无布局差异、拖拽被禁用;Esc / 遮罩关闭与焦点陷阱、ARIA 行为照常。
全屏对话框
全屏对话框铺满视口、无圆角与边距。width / centered 被忽略、拖拽被禁用,Esc / 遮罩关闭照常。
可最大化(maximizable)
maximizable 在标题栏 ✕ 左侧显示最大化/还原按钮:最大化等同 fullscreen 语义(铺满视口、无圆角、width 被忽略、拖拽失效),再点还原回原尺寸;切换派发 oas-maximize(detail.maximized 标明状态)。显式设置 fullscreen 属性时按钮隐藏(宿主已强制全屏,切换无意义)。
可最大化对话框
点标题栏的最大化按钮铺满视口,再点还原;每次切换派发 oas-maximize(右上角消息反馈)。
命令式确认
confirm() 命令式 API 基于 Promise,底层复用 oas-modal(返回 Promise<void>,确定 resolve、取消 reject)。传 onOk 异步回调可实现 loading 态确认:点击确定后 OK 按钮进入 loading(转圈、禁止重复触发),onOk resolve 后自动关闭并 resolve 外层 Promise;reject 则清除 loading、对话框保持打开可重试或取消。
命令式确认
命令式确认框(modal API)
modal.confirm / info / success / warning / error 命令式 API 返回 { close() } 句柄,底层复用 oas-modal。选项:title、content(纯文本,杜绝 HTML 注入)、okText、cancelText、onOk、onCancel。传异步 onOk(返回 Promise)时点击确定后 OK 按钮进入 loading(转圈、禁止重复触发),resolve 自动关闭、reject 清除 loading 保持打开可重试或取消。取消按钮 / ✕ / 遮罩 / Esc 触发 onCancel 后关闭;句柄 close() 可编程关闭(不触发 onCancel)。多实例可叠放共存,destroyAllModal() 一次关闭全部;挂载到最近 oas-app 容器(无则 body)。
基础确认
语义变体
异步 onOk loading
多例与销毁全部
声明式语义变体
命令式模块内部使用的 type / ok-text / cancel-text / no-cancel / focus-ok 均为 oas-modal 公开属性,可声明式使用。
声明式语义变体
type 渲染语义图标;ok-text/cancel-text 自定义按钮文案;focus-ok 打开时聚焦「确定」。
no-cancel 隐藏取消按钮,底部仅剩「确定」。
事件反馈
事件反馈
点击「确定」或「取消」,观察右上角消息提示。
Prompt 输入框
modal.prompt(options) 命令式输入框:打开自动聚焦输入框,结果 resolve { value, action }(action:确定为 confirm,取消 / ✕ / 遮罩 / Esc 统一为 cancel)。支持 inputValue / placeholder / inputType(text / password / number / textarea)/ inputPattern(字符串正则校验,先 pattern 后 validator)/ validator(返回 true 通过、false 用默认文案、string 即错误文案)。校验失败保持打开并显示错误,输入修正后自动清除可再提交;异步 onOk 时确定按钮进入 loading。
prompt 能力(主路径已默认内含):主路径
@oas-ui/ui/feedback/modal已内置 prompt 能力(import 即注册),无需显式引用。若想保留不含 prompt machinery 的纯核瘦身(确认/提示类消费者零开销),可改从纯核入口@oas-ui/ui/feedback/modal/core引入——它不含该能力,此时调用modal.prompt返回null并在 dev 控制台告警一次,需显式引用:tsimport '@oas-ui/ui/feedback/modal/prompt'或换回主路径。全量入口
@oas-ui/ui与 CDN 反馈族包同样已内含。
prompt 基础输入
prompt 进阶(textarea / password + pattern)
body 滚动锁
打开时锁定 body 滚动(overflow hidden + 滚动条宽度补偿防跳动),关闭还原;多实例嵌套计数,全部关闭才解锁。no-scroll-lock 可关闭该行为。
body 滚动锁
打开后页面滚动被锁定;关闭后恢复。试试打开状态下滚动页面,内容不再移动。
关闭拦截(before-close)
监听可取消的 oas-before-close(event.detail.source 标明来源:ok / cancel / close-btn / mask / esc),preventDefault() 可阻止关闭——表单未保存等数据保护场景。命令式确认框的确定路径由 onOk Promise 控制(resolve 才关闭),取消类路径同样可被拦截。
关闭拦截
点「取消」/ ✕ / 遮罩 / Esc 都会被拦截并提示;点「保存」正常关闭。
关闭入口三开关
no-esc-close(禁 Esc)、no-mask-close(禁遮罩点击)、no-close-btn(隐藏 ✕)——三个关闭入口各自独立可配,把关闭控制权交给宿主。
关闭入口三开关
Esc 与 ✕ 均不可用(遮罩点击仍可关闭),关闭入口只剩底部按钮。
自定义底部(footer 插槽)
slot="footer" 有内容时自动隐藏内置确定/取消按钮,底部完全由插槽接管。
footer 插槽
底部按钮由插槽完全接管(内置确定/取消自动隐藏)。
运行时更新(handle.update)
handle.update(partialOptions) 运行时增量更新标题 / 内容 / 按钮文案,不影响已绑定的回调。
handle.update()
命令式语义 alertdialog
命令式确认框 / prompt 的 dialog 语义为 role="alertdialog"(读屏立即打断播报);声明式 <oas-modal> 缺省保持 dialog,可用 role 属性手动指定。
alertdialog 语义
role="alertdialog":读屏立即打断当前播报;声明式缺省为 dialog。
遮罩样式与顶部贴边
遮罩背景走 --oas-modal-mask-bg 变量(缺省 overlay token),--oas-modal-mask-blur 可选背景模糊;position="top" 让对话框贴视口顶缘(默认靠上偏移 100px,centered 时居中)。
遮罩样式 / position top
遮罩背景来自 --oas-modal-mask-bg(此处红色 18% + 2px 模糊)。
position="top" 让对话框贴视口顶缘;默认靠上偏移 100px(centered 时垂直居中)。
层级(z-index)
z-index 显式覆盖默认 modal 档位(--oas-z-modal):数值叠加在 --oas-z-index-base(config-provider 浮层起始值)之上,对话框恒比遮罩高 1;缺省走默认档位。多实例叠开时可用它精确控制谁在上。
层级覆盖(z-index)
这是默认层级的对话框。点上面的按钮再叠开一个显式 z-index 的对话框,观察覆盖关系。
z-index="3000":遮罩与对话框层级显式抬升(对话框仍比遮罩高 1),盖在底层对话框之上;Esc 先关最上层。
关闭来源事件
oas-close 携带 detail.source(ok / cancel / close-btn / mask / esc / programmatic)与 detail.action(confirm / cancel / close);非确定路径保留 oas-cancel(旧语义)。
关闭来源
分别用确定 / 取消 / ✕ / 遮罩 / Esc 关闭,观察右上角来源消息。
开合动画
打开 / 关闭默认播放 fade + scale 动画(只走 transform/opacity,prefers-reduced-motion 下自动停用)。oas-open 在打开开始派发,oas-after-open / oas-after-close 在动画结束后派发——命令式对话框据此「等动画结束再卸载」。transition 可选预设:zoom(默认,淡入 + 缩放)/ fade(仅淡入淡出)/ none(无过渡、即时显隐)。
开合动画 + 生命周期事件
默认 fade + scale 动画;右上角消息展示 oas-after-open / oas-after-close(动画结束才派发)。
transition 预设(fade / none)
transition="fade":只做透明度过渡,不做缩放。
transition="none":打开 / 关闭即时显隐(适合高性能或降级场景)。
点击位置动画原点
打开瞬间会记录触发指针的位置,对话框从该点向外展开(transform-origin 指向点击处);键盘 / 编程打开时回退居中展开。
点击位置动画原点
缩放动画的原点跟随最近一次点击位置:从你点击的按钮处向外展开,而不是固定在中心。
非模态(no-mask)
no-mask:遮罩不渲染 + 焦点陷阱关闭 + 打开不抢焦点(语义对齐原生 <dialog>.show(),适合通知 / 画布辅助等非中断场景)。关闭通道照常(✕ / 底部按钮 / Esc;Esc 可另行用 no-esc-close 关闭)。
no-mask 非模态
无遮罩、焦点不被圈禁——页面其余部分仍可交互(试试打开后点页面上的按钮)。
拖拽钳制(keep in viewport)
对话框可拖拽时,坐标被钳制在视口内(默认开启):即使大幅拖动也不会整框拖出视口找不回。
拖拽钳制
按住标题栏随便拖:对话框始终留在视口内(右 / 下边缘被钳住),不会拖出找不回。
声明式 trigger
trigger="元素id" 把任意页面元素绑定为打开触发器:点击该元素即 setAttribute('visible')(纯语法糖,不改变受控模型——关闭仍需宿主移除 visible)。
声明式 trigger
这个按钮没有写任何 onclick——由 oas-modal 的 trigger 属性自动绑定点击打开。
尺寸预设与全屏断点
size 预设档位:sm(400px)/ lg(720px),显式 width 优先。fullscreen-breakpoint="800":视口宽度低于阈值自动进入全屏(拖宽视口自动还原),移动端窄屏适配无需 JS 监听。
尺寸预设 sm / lg
size="sm":宽度 400px。
size="lg":宽度 720px。
fullscreen-breakpoint
fullscreen-breakpoint="800":视口宽度低于 800px 自动铺满全屏(无圆角、忽略宽度);拉宽后自动还原为常规对话框。
回车确认(confirm-on-enter)
confirm-on-enter(显式开启,默认关):弹窗内没有文本输入控件时按 Enter 触发「确定」(loading 中忽略;焦点在按钮上时交还按钮原生激活,避免重复触发)。适合快速确认类对话框。
confirm-on-enter
点击正文空白处让焦点离开按钮,再按 Enter —— 等同点击「确定」。弹窗内若放了输入框,Enter 不会被劫持。
拦截抖动反馈(shake)
oas-before-close 被 preventDefault() 拦截(数据保护等场景)时,对话框播放一次水平抖动提示「这条关闭路径不可用」;动画结束后自动移除,可重复触发。
shake 防误关反馈
此对话框拦截取消类关闭:点「取消」/ ✕ / Esc 会看到对话框抖动提示,不会真的关闭。
自定义关闭图标(close-icon 插槽)
slot="close-icon" 覆盖默认 ✕,富内容自定义关闭图标(aria-label 语义保持)。
close-icon 插槽
右上角关闭图标由插槽接管(此处为自定义样式)。
✕options 选项模式
modal.options({ items, type }) 命令式选择框:确认框内嵌选项组,结果 resolve { value, action }。type:radio(单选,value 为字符串)/ checkbox(多选,数组)/ toggle(开关组,数组);支持 disabled 项、异步 onOk loading、close() / update() 句柄(与 prompt 同形态)。
options 单选 / 多选 / 开关
渲染策略
destroy-on-close 关闭后清空内容节点(下次打开前重新填充);append-to 把对话框挂载到指定容器(突破宿主 overflow 裁切)。
destroy-on-close / append-to
关闭后内容被清空;再次打开前由按钮重新填充。
对话框已挂载到 body 级容器(portal),即使宿主在 overflow:hidden 容器内也不被裁切。
焦点陷阱与滚动锁开关
initial-focus 指定打开时聚焦的元素(CSS 选择器,面板内优先、其次 light DOM,无匹配回退默认焦点);no-focus-trap 关闭 Tab 焦点圈禁(焦点交给宿主自管的场景);no-scroll-lock 关闭 body 滚动锁(页面可继续滚动)。
initial-focus / no-focus-trap / no-scroll-lock
打开后焦点直接落在输入框(initial-focus);不圈禁 Tab、不锁页面滚动。
媒体区(media 插槽)
slot="media" 提供正文顶部的媒体区(图标 / 插图 / 缩略图等富媒体),有内容才显示——未提供内容时该区域不渲染、不占位。
media 媒体插槽
顶部媒体区来自 slot="media";未提供内容时该区域不渲染、不留白。
页脚吸底(sticky-footer)
sticky-footer 让正文区在 --oas-modal-body-max-height(默认 60vh)内滚动,页脚常驻对话框底部、不随正文滚走(全屏态自动豁免该限高)。默认关闭——不设时布局与原来完全一致;可在宿主上覆盖该变量调整正文滚动区高度。
sticky-footer 页脚吸底
正文很长(此块高 90vh):正文区在限定高度内滚动,底部按钮始终吸底可见。
API
方法
| 方法 | 说明 |
|---|---|
modal.confirm({ title?, content?, okText?, cancelText?, onOk?, onCancel? }) | 打开确认框(确定/取消双按钮),返回 { close } |
modal.info(options) / modal.success(options) / modal.warning(options) / modal.error(options) | 语义确认框:对应图标 + 单「确定」按钮,返回 { close } |
modal.prompt({ title?, inputValue?, placeholder?, inputType?, validator?, onOk? }) | 输入框确认:结果 resolve { value, action },返回 Promise & { close, update } |
modal.options({ title?, content?, items?, type?, okText?, cancelText?, onOk? }) | 选项选择框(type:radio / checkbox / toggle):结果 resolve { value, action }(radio 单个字符串;checkbox/toggle 数组),返回 Promise & { close, update } |
destroyAllModal() | 关闭并销毁全部命令式确认框(等各自关闭动画结束) |
- 选项:
{ title?, content?, okText?, cancelText?, onOk?, onCancel? }。content为纯文本;onOk返回 Promise 时确定按钮进入 loading(resolve 关闭、reject 保持打开可重试或取消)。 - 返回
{ close() }句柄:编程关闭当前实例,不触发onOk/onCancel。 - 挂载到最近
oas-app容器(无则body);多实例可叠放;命令式实例在关闭动画结束(oas-after-close)后才卸载。
oas-modal
属性
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
append-to | portal 挂载点:把遮罩与对话框移入目标容器(body 或 CSS 选择器)内的独立 shadow(样式作用域保真),脱离宿主 overflow 裁剪;属性移除/无匹配时移回宿主 shadow | — | — |
cancel-text | 取消按钮文案;缺省走 locale modal.cancel | — | — |
centered | 对话框垂直居中显示 | boolean | — |
confirm-on-enter | 显式开启后回车触发确定(仅最上层响应;弹窗内无文本输入控件且焦点不在按钮/链接等原生交互控件上才生效,防双触发;默认关闭) | boolean | — |
destroy-on-close | 关闭动画完成后清空宿主子内容(下次打开重新渲染) | boolean | — |
draggable | 可通过标题栏拖动对话框 | boolean | — |
focus-ok | 打开时焦点移入「确定」按钮(默认移入「取消」按钮) | boolean | — |
fullscreen | 全屏显示:对话框铺满视口、无圆角与边距(优先级高于 width / centered / draggable) | boolean | — |
fullscreen-breakpoint | 视口宽度低于该阈值(px)时自动全屏(打开期间随 resize 重算;与显式 fullscreen 取并集) | — | — |
initial-focus | 打开时聚焦指定选择器元素(对话框内优先,其次宿主 light DOM);未设置回落 focus-ok / 取消按钮 / 确定 / ✕ | — | — |
loading | 确定按钮进入 loading 态(禁用 + 转圈),禁止重复触发确定 | boolean | — |
maximizable | 标题栏显示最大化/还原按钮:最大化等同 fullscreen 语义,再点还原;显式 fullscreen 下隐藏 | boolean | — |
no-cancel | 隐藏取消按钮(底部仅剩「确定」;语义变体确认框内置) | boolean | — |
no-close-btn | 隐藏标题栏 ✕ 关闭按钮 | boolean | — |
no-esc-close | 禁用 Esc 关闭(Esc 仅由最上层可见 modal 响应) | boolean | — |
no-focus-trap | 关闭焦点陷阱(Tab 不再圈定在对话框内) | boolean | — |
no-footer | 隐藏底部操作按钮 | boolean | — |
no-mask | 无遮罩非模态:遮罩不渲染、焦点陷阱关闭、打开时不抢焦点(对齐 HTML dialog.show(),可与页面其余部分交互) | boolean | — |
no-mask-close | 禁用点击遮罩关闭 | boolean | — |
no-scroll-lock | 打开时不锁定 body 滚动(默认锁定时带滚动条宽度补偿,防布局跳动) | boolean | — |
ok-text | 确定按钮文案;缺省走 locale modal.ok | — | — |
position | 垂直定位:top 贴视口顶缘;缺省距顶 100px;与 centered 同设时 top 规则后置生效 | — | — |
role | 对话框 ARIA 角色(默认 dialog;语义变体确认场景可设 alertdialog) | string | dialog |
size | 尺寸预设:sm(400px)/ lg(720px);width 显式值优先;非法值回落主题默认 520px | ModalSizePreset | — |
sticky-footer | 页脚吸底:正文区在 --oas-modal-body-max-height(默认 60vh)内滚动、页脚常驻对话框底部不随正文滚走;全屏态(data-fullscreen)自动豁免该限高。默认关闭——不设时布局不变(非破坏) | — | — |
title | 标题文案(渲染进可见标题区;读取后即从宿主移除,不残留原生悬浮提示;清空传空串);富内容用 slot="title" | string | — |
transition | 开合动画预设:zoom(默认,淡入 + 缩放,缩放原点跟随打开前的点击位置)/ fade(仅透明度)/ none(无过渡即时显隐) | — | — |
trigger | 声明式触发元素 id:点击该元素设置 visible 打开弹窗(不动受控模型);元素不存在时静默,后续 update 重试 | — | — |
type | 语义变体:info/success/warning/error,正文顶部渲染对应语义图标 | ModalVariant | — |
visible | 是否显示 | boolean | — |
width | 对话框宽度(px 或百分比) | — | — |
z-index | 显式层级基准(叠加在 --oas-z-index-base 之上,对话框比遮罩高 1;缺省走 --oas-z-modal 档位) | — | — |
事件
| 事件 | 说明 |
|---|---|
oas-after-close | 关闭动画完成(规范名,对齐 after-* 家族),detail 无;destroy-on-close 清空内容在此之后 |
oas-after-open | 打开动画完成(规范名,对齐 after-* 家族),detail 无;等价 oas-opened |
oas-before-close | 关闭请求前派发(确定/取消/✕/遮罩/Esc),cancelable,detail: { source };preventDefault 阻止关闭并触发对话框 shake 提示(programmatic 关闭绕过拦截) |
oas-cancel | 取消:取消按钮 / ✕ / 遮罩点击 / Esc |
oas-close | 开始关闭时派发,detail: { source, action }(source: ok/cancel/close-btn/mask/esc/programmatic;action: confirm/cancel/close) |
oas-closed | 【兼容别名】关闭动画完成,等价 oas-after-close;后续版本移除 |
oas-maximize | 最大化/还原切换时派发,detail: { maximized } |
oas-ok | 点击「确定」 |
oas-open | 开始打开时派发(锁滚动、焦点移入之后),detail 无 |
oas-opened | 【兼容别名】打开动画完成,等价 oas-after-open;后续版本移除 |
插槽
| 名称 | 说明 |
|---|---|
| 默认 | 对话框主体内容 |
close-icon | 自定义关闭图标(替代默认 ✕) |
description | 描述文案(标题下方说明) |
footer | 底部操作区 |
media | 媒体区插槽(图标 / 插图 / 缩略图等富媒体),正文顶部居中;有内容才显示,无内容不占位 |
title | 标题富内容插槽,有内容时覆盖 title 属性文案 |
CSS 变量
| CSS 变量 | 默认值 |
|---|---|
--oas-glass-blur | none |
--oas-glass-ring | transparent |
--oas-modal-body-max-height | 60vh |
--oas-modal-mask-bg | var(--oas-color-overlay) |
--oas-modal-mask-blur | 0px |
--oas-modal-max-height | 90vh |
--oas-modal-origin-x | center |
--oas-modal-origin-y | center |
role="dialog" + aria-modal="true",打开时焦点移入「取消」按钮(focus-ok 时移入「确定」按钮),关闭后还原。