它是如何工作的
Dialog 组件利用浏览器原生的 <dialog> 元素,提供内置的无障碍功能、焦点管理和背景处理,而无需复杂的自定义实现。
本地对话的主要特点:
- 模态或内联 通过
showModal()/show()—modal: true(默认)将对话框提升到浏览器的顶层,并带有背景遮罩和焦点锁定;modal: false则以内联方式渲染。 - 内置背景遮罩 使用
::backdrop伪元素(仅限模态);设置backdrop: "static"锁定外部点击,或设置backdrop: false隐藏它。 - Esc 键处理 默认关闭对话框;设置
keyboard: false可禁用该功能。 - 无障碍性 — 对话框内部焦点被锁定,并在关闭时返回到触发元素,同时具有原生
<dialog>ARIA 语义。 - 动画开关 — 通过使用
.hiding类在关闭期间保持对话框在顶层,从而正确执行退出过渡(包括::backdrop)的动画,绕过浏览器限制。
此组件的动画效果取决于 prefers-reduced-motion 媒体查询。请参阅我们无障碍文档中的 减少动画部分。
示例
通过点击下面的按钮切换对话框。该对话框使用原生 showModal() API 实现真正的模态行为。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#exampleDialog">
Open dialog
</button>
<dialog class="dialog" id="exampleDialog">
<div class="dialog-header">
<h1 class="dialog-title">Dialog title</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This is a native dialog element. It uses the browser’s built-in modal behavior for accessibility and focus management.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>没有 JavaScript
支持的浏览器可以使用 Invoker Commands API 打开和关闭对话框——无需 Bootstrap JavaScript。将 commandfor 设置为对话框的 id,使用 command="show-modal" 打开,使用 command="close" 关闭。
Invoker Commands API 并非所有浏览器都支持。为了确保支持,当你需要我们的插件选项、事件或动画关闭时,请使用上面的 data-bs-toggle 示例。
<button type="button" class="btn-solid theme-primary" commandfor="invokerDialog" command="show-modal">
Open dialog
</button>
<dialog class="dialog" id="invokerDialog">
<div class="dialog-header">
<h1 class="dialog-title">Invoker Commands</h1>
<button type="button" class="btn-close" commandfor="invokerDialog" command="close" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog opens with <code>command="show-modal"</code> and closes with <code>command="close"</code>. No Bootstrap JavaScript is involved.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" commandfor="invokerDialog" command="close">Close</button>
</div>
</dialog>深色对话
要使对话变暗,请添加 data-bs-theme="dark" 到 <dialog> 元素。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#exampleDialogDark">
Open dark dialog
</button>
<dialog class="dialog" id="exampleDialogDark" data-bs-theme="dark">
<div class="dialog-header">
<h1 class="dialog-title">Dark dialog title</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This is a native dialog element, only it’s set to dark mode. It uses the browser’s built-in modal behavior for accessibility and focus management.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>静态背景
当 backdrop 设置为 static 时,点击对话框外部时对话框不会关闭。点击下面的按钮来试一试。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#staticBackdropDialog" data-bs-backdrop="static">
Open static backdrop dialog
</button>
<dialog class="dialog" id="staticBackdropDialog">
<div class="dialog-header">
<h1 class="dialog-title">Static backdrop</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>I will not close if you click outside of me. Use the close button or press Escape.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
</div>
</dialog>覆盖层
工具提示、弹出框和轻提示在对话框内都能工作,但需要一些额外的注意。由于对话框在浏览器的顶层渲染,附加到<body>的覆盖层将出现在对话框的后面。将data-bs-container设置为对话框元素,这样工具提示和弹出框就会在其中渲染。只要轻提示放在对话框标记中,它们已经可以正常工作。
工具提示、弹出框、消息提示和菜单都可以在对话框中使用。对话框使用showModal(),它将对话框提升到浏览器的顶层——页面上所有内容之上的特殊渲染层。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#dialogWithComponents">
Open dialog
</button>
<dialog class="dialog not-prose" id="dialogWithComponents">
<div class="dialog-header">
<h1 class="dialog-title">Overlays inside dialogs</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>These components work inside modal dialogs.</p>
<div class="d-flex gap-2 flex-wrap">
<button type="button" class="btn-solid theme-secondary" data-bs-toggle="tooltip" data-bs-title="Tooltip inside a dialog!">Tooltip</button>
<button type="button" class="btn-solid theme-secondary" data-bs-toggle="popover" data-bs-title="Popover title" data-bs-content="This popover is inside a dialog and renders in the top layer. We include some longer content here to demonstrate the placement and wrapping behavior." data-bs-placement="top">Popover</button>
<button type="button" class="btn-solid theme-secondary" id="dialogToastBtn">Show toast</button>
<button class="btn-solid theme-secondary" type="button" data-bs-toggle="menu" aria-expanded="false">Menu</button>
<div class="menu">
<a class="menu-item" href="#">Action</a>
<a class="menu-item" href="#">Another action</a>
<hr class="menu-divider" />
<div class="submenu">
<button class="menu-item" type="button">More options</button>
<div class="menu">
<a class="menu-item" href="#">Sub-action A</a>
<a class="menu-item" href="#">Sub-action B</a>
<div class="submenu">
<button class="menu-item" type="button">Even more</button>
<div class="menu">
<a class="menu-item" href="#">Deep action 1</a>
<a class="menu-item" href="#">Deep action 2</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div class="toast" id="dialogToast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-body">
Toast inside a dialog!
<div class="mt-2 pt-2 border-top">
<button type="button" class="btn-solid theme-primary btn-sm" data-bs-dismiss="toast">Close</button>
</div>
</div>
</div>
</div>
</dialog>动画
即时
默认情况下,对话框在打开和关闭时会淡入淡出动画。要禁用动画,请添加 .dialog-instant 到 <dialog> 元素。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#instantDialog">
Instant dialog
</button>
<dialog class="dialog dialog-instant" id="instantDialog">
<div class="dialog-header">
<h1 class="dialog-title">Instant dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog doesn’t animate and appears instantly on open and close.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>向下滑动
添加 .dialog-slide-down 到 <dialog> 它会滑动 下 在打开时从视口顶部开始。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#slideDownDialog">
Slide down dialog
</button>
<dialog class="dialog dialog-slide-down" id="slideDownDialog">
<div class="dialog-header">
<h1 class="dialog-title">Slide down dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog slides down from the top of the viewport.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>向上滑动
添加 .dialog-slide-up 到 <dialog> 它会滑动 向上 在打开时从视口底部。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#slideUpDialog">
Slide up dialog
</button>
<dialog class="dialog dialog-slide-up" id="slideUpDialog">
<div class="dialog-header">
<h1 class="dialog-title">Slide up dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog slides up from the bottom of the viewport.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>可滚动
创建一个可滚动的对话框,使对话框主体可以滚动,同时保持头部和底部固定。将.dialog-scrollable添加到.dialog元素中。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#scrollableBodyDialog">
Launch scrollable body dialog
</button>
<dialog class="dialog dialog-scrollable" id="scrollableBodyDialog">
<div class="dialog-header">
<h1 class="dialog-title">Scrollable body</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This is some placeholder content to show the scrolling behavior for dialogs. We use repeated line breaks to demonstrate how content can exceed the dialog’s inner height, showing scrolling within the body while the header and footer remain fixed.</p>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<p>This content should appear at the bottom after you scroll.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>交换对话
当切换触发器位于已打开的对话框内时,点击它将 交换 对话框——在关闭当前对话框之前打开新的对话框。这可确保在过渡过程中背景保持可见且没有闪烁。当data-bs-toggle="dialog"触发器位于已打开的对话框内时,交换行为是自动的。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#swapDialog1">
Open first dialog
</button>
<dialog class="dialog" id="swapDialog1">
<div class="dialog-header">
<h1 class="dialog-title">First dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>Click below to swap to a second dialog. Notice the backdrop stays visible—no flash!</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#swapDialog2">Go to second dialog</button>
</div>
</dialog>
<dialog class="dialog" id="swapDialog2">
<div class="dialog-header">
<h1 class="dialog-title">Second dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This is the second dialog. You can swap back to the first, or close this one entirely.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#swapDialog1">Back to first dialog</button>
</div>
</dialog>非对话框
默认情况下,对话框使用浏览器原生功能以模态形式打开 showModal() 方法。你也可以使用非模态方式打开对话框 show() 通过设置 modal 到 false. 非对话框:
- 没有背景
- 不要限制焦点
- 不要阻止与页面其他部分的交互
- 不要在浏览器的顶层渲染
- 仍然响应 Esc 键(如果
keyboard: true)
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#nonModalDialog" data-bs-modal="false">
Open non-modal dialog
</button>
<dialog class="dialog" id="nonModalDialog">
<div class="dialog-header">
<h1 class="dialog-title">Non-modal dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog doesn’t block the page. You can still interact with content behind it.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
</div>
</dialog>如果使用 JavaScript 构建,请使用 modal 选项来创建非对话框:
const dialog = new bootstrap.Dialog('#myDialog', { modal: false })
dialog.show()
可选尺寸
对话框有三种可选大小,可通过修饰类放置在.dialog上使用。这些大小在特定断点时生效,以避免在较窄的视口上出现水平滚动条。
| 尺寸 | 类名 | 对话框最大宽度 |
|---|---|---|
| 小 | .dialog-sm | 280px |
| 默认 | — | 500px |
| 大 | .dialog-lg | 800px |
| 超大 | .dialog-xl | 1140px |
<dialog class="dialog dialog-xl">…</dialog>
<dialog class="dialog dialog-lg">…</dialog>
<dialog class="dialog">…</dialog>
<dialog class="dialog dialog-sm">…</dialog>
全屏对话框
使用 .dialog-fullscreen 使对话框覆盖整个视口。
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#exampleDialogFullscreen">
Fullscreen dialog
</button>
<dialog class="dialog dialog-fullscreen" id="exampleDialogFullscreen">
<div class="dialog-header">
<h1 class="dialog-title">Fullscreen dialog</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog covers the entire viewport.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
</div>
</dialog>响应式全屏变体也可用。这些变体仅在低于特定断点时使对话框全屏显示。
| 类名 | 小于该尺寸时全屏 |
|---|---|
.dialog-fullscreen | 总是 |
.sm-down:dialog-fullscreen | 576px |
.md-down:dialog-fullscreen | 768px |
.lg-down:dialog-fullscreen | 1024px |
.xl-down:dialog-fullscreen | 1280px |
.2xl-down:dialog-fullscreen | 1536px |
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#exampleDialogFullscreenLg">
Fullscreen below lg
</button>
<dialog class="dialog lg-down:dialog-fullscreen" id="exampleDialogFullscreenLg">
<div class="dialog-header">
<h1 class="dialog-title">Fullscreen below lg</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="关闭"></button>
</div>
<div class="dialog-body">
<p>This dialog is fullscreen below the <code>lg</code> breakpoint.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
</div>
</dialog>CSS
变量
// stylelint-disable-next-line scss/dollar-variable-default
$dialog-tokens: defaults(
(
--dialog-padding: 1rem,
--dialog-width: 500px,
--dialog-margin: 1.75rem,
--dialog-color: var(--fg-body),
--dialog-bg: var(--bg-body),
--dialog-border-color: var(--border-color-translucent),
--dialog-border-width: var(--border-width),
--dialog-border-radius: var(--radius-7),
--dialog-box-shadow: var(--box-shadow-xl),
--dialog-transition-property: "opacity, transform, visibility",
--dialog-transition-duration: .3s,
--dialog-transition-timing: var(--transition-timing-overlay),
--dialog-backdrop-bg: light-dark(rgb(0 0 0 / 50%), rgb(0 0 0 / 65%)),
--dialog-backdrop-blur: 8px,
--dialog-header-padding: 1rem,
--dialog-header-border-color: var(--border-color-translucent),
--dialog-header-border-width: var(--border-width),
--dialog-footer-padding: 1rem,
--dialog-footer-border-color: var(--border-color-translucent),
--dialog-footer-border-width: var(--border-width),
--dialog-footer-gap: .5rem,
),
$dialog-tokens
);
Sass map
对话框尺寸在 $dialog-sizes Sass map中定义。每种尺寸指定对话框的 width。
$dialog-sizes: ();
// stylelint-disable-next-line scss/dollar-variable-default
$dialog-sizes: defaults(
(
sm: 280px,
lg: 800px,
xl: 1140px,
),
$dialog-sizes
);
JavaScript 行为
通过数据属性
无需编写 JavaScript 即可切换对话框。在控制元素(如按钮)上设置 data-bs-toggle="dialog",并使用 data-bs-target="#foo" 来定位要切换的特定对话框。
| 属性 | 描述 |
|---|---|
data-bs-toggle="dialog" | 从触发元素打开或切换对话框。 |
data-bs-target | 要显示或隐藏的对话框元素的 CSS 选择器。 |
data-bs-dismiss="dialog" | 在对话框内的控件上激活时,关闭对话框。 |
<button type="button" data-bs-toggle="dialog" data-bs-target="#myDialog">
Launch dialog
</button>
解雇
解雇可以通过 data-bs-dismiss 按钮上的属性 在对话中:
<button type="button" data-bs-dismiss="dialog">Close</button>
通过 JavaScript
用一行 JavaScript 创建一个对话框:
const myDialog = new bootstrap.Dialog('#myDialog')
依赖项
如果你从源代码构建 Bootstrap 的 JS,则对话框插件需要以下 JavaScript 文件:
| 文件 | 描述 |
|---|---|
js/src/dialog.ts | 主对话组件 |
js/src/base-component.ts | 基础组件类 |
js/src/dialog-base.ts | 基础对话组件 |
js/src/dom/data.ts | 元素数据存储 |
js/src/dom/event-handler.ts | 事件处理工具 |
js/src/dom/manipulator.ts | 数据属性操作 |
js/src/dom/selector-engine.ts | DOM选择器工具 |
js/src/util/component-functions.ts | 共享组件助手 |
js/src/util/config.ts | 配置基类 |
js/src/util/index.ts | 核心实用功能 |
选项
选项可以通过数据属性或 JavaScript 传递。对于数据属性,将选项名称附加到 data-bs-,如data-bs-backdrop="static"所示。
| 名称 | 类型 | 默认 | 描述 |
|---|---|---|---|
backdrop | 布尔或 'static' | true | 对于对话框,点击背景可关闭对话框。指定 static 用于点击时不会关闭对话框的背景。对非对话框无效。 |
keyboard | boolean | true | 按下退出键时关闭对话框。 |
modal | boolean | true | 什么时候 true,使用…以模态方式打开对话框 showModal() 带有背景、焦点捕获和顶层渲染时 false,以非对话框的形式打开,使用 show() 没有背景遮罩或焦点锁定。 |
方法
显示或隐藏组件的方法会返回一个 Promise。 当过渡结束时,该 Promise 会被解析,所以 await 会在 shown.bs.* 或 hidden.bs.* 监听器运行的同一时刻继续。方法仍会立即返回,并且永远不会阻塞调用者。对已在过渡中的组件进行调用不会有任何效果,并会立即解析。在我们的 JavaScript 文档中了解更多。
传球选项
将你的内容激活为对话框。接受一个可选的选项对象。
const myDialog = new bootstrap.Dialog('#myDialog', {
keyboard: false
})
| 方法 | 描述 |
|---|---|
show | 打开对话框。 返回一个在对话框显示后解析的 Promise (即在……之后 shown.bs.dialog 事件触发)。 |
hide | 隐藏对话框。 返回一个在对话框被隐藏后解决的 promise (即在……之后 hidden.bs.dialog 事件触发)。 |
toggle | 切换对话框。 返回一个在对话框显示或隐藏后解析的承诺 (即在……之后 shown.bs.dialog 或 hidden.bs.dialog 事件触发)。 |
handleUpdate | 为了与 Modal 的 API 保持一致而提供。原生对话框自行处理其位置。 |
dispose | 销毁元素的对话框。 |
getInstance | 静态方法,允许你获取与 DOM 元素关联的对话框实例。 |
getOrCreateInstance | 静态方法,允许你获取与 DOM 元素关联的对话框实例,或者在尚未初始化时创建一个新的实例。 |
事件
Bootstrap 的对话框类提供了一些事件,用于连接到对话框功能。
| 事件 | 描述 |
|---|---|
show.bs.dialog | 在……时立即点火 show 实例方法被调用。 |
shown.bs.dialog | 当对话框对用户可见时触发(会等待 CSS 过渡完成)。 |
hide.bs.dialog | 在……时立即点火 hide 实例方法被调用。 |
hidden.bs.dialog | 当对话框被隐藏且用户看不见时触发(会等待 CSS 过渡完成)。 |
hidePrevented.bs.dialog | 当对话框显示时触发,其背景是 static,并且在对话框外点击或按下退出键时(使用 keyboard 设置为 false). |
cancel.bs.dialog | 当用户按下 Escape 并且对话框即将关闭时触发。 |
const myDialog = document.getElementById('myDialog')
myDialog.addEventListener('hidden.bs.dialog', event => {
// do something...
})