它是如何工作的
抽屉基于原生的<dialog>元素和我们的对话框组件,通过 JavaScript 管理隐藏的侧边栏。这些侧边栏,或称抽屉,可以从视口的左、右、上或下边缘出现。按钮或锚点作为触发器,用于绑定到你要切换的特定元素,data属性用于调用我们的 JavaScript。
- 抽屉与……有相同的底座 我们的对话框组件,使用本地
<dialog>用于焦点锁定、背景和顶层渲染的 API。 - 使用
<dialog>元素,不是一个<div>由于 CSS 处理动画的方式,请不要应用margin或translate直接到.drawer——如果你需要的话就包起来。 - 默认模态 ——以……开场
showModal(),一个背景,以及焦点捕捉。设置scroll: true和backdrop: false以非模态抽屉方式打开,并带有show(): 页面滚动保持开启,焦点不会被限制。 - 内置背景 通过
::backdrop(仅限模态)点击时关闭抽屉;设置backdrop: "static"锁定外部点击,或backdrop: false隐藏它。 - Esc键处理 默认情况下关闭抽屉;设置
keyboard: false禁用。 - 滑动以关闭 — 抽屉自动连接一个感知位置的滑动(向左滑动以关闭)
drawer-start在LTR中,下滑以关闭drawer-bottom等等)。 - 响应式布局 —
.sm:drawer,.md:drawer并且在它们的断点以下保持抽屉状,在断点以上以内联形式折叠,使抽屉在响应式导航栏中有用。 - 一次只能显示一个抽屉 (由数据 API 强制执行)。
- 动画开合 — 抽屉在关闭时滑回到其特定位置的屏幕外位置,带有
::backdrop在以模态方式打开时同时淡出。在编写自定义 CSS 时,请限定你的[open]规则与:not(.hiding)所以退出过渡可以落入基础状态;添加.drawer-instant跳过动画。
此组件的动画效果取决于 prefers-reduced-motion 媒体查询。请参阅我们无障碍文档中的 减少动画部分。
示例
抽屉组件
以下是一个默认显示的抽屉示例(通过open和.show在<dialog>上)。抽屉支持带关闭按钮的标题以及可选的主体类,用于一些初始的padding。我们建议你尽可能在抽屉标题中包含关闭操作,或者提供明确的关闭操作。
<dialog class="drawer drawer-start show" open tabindex="-1" id="drawer" aria-labelledby="drawerLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerLabel">Drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
Content for the drawer goes here. You can place just about any Bootstrap component or custom elements here.
</div>
</dialog>现场演示
使用下面的按钮通过 JavaScript 显示和隐藏抽屉元素。你可以使用带有 href 属性的链接,或带有 data-bs-target 属性的按钮。在这两种情况下,都需要 data-bs-toggle="drawer"。
<a class="btn-solid theme-primary" data-bs-toggle="drawer" href="#drawerExample" role="button" aria-controls="drawerExample">
Link with href
</a>
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerExample" aria-controls="drawerExample">
Button with data-bs-target
</button>
<dialog class="drawer drawer-start" tabindex="-1" id="drawerExample" aria-labelledby="drawerExampleLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerExampleLabel">Drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<div>
Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
</div>
<div class="mt-3">
<button class="btn-solid theme-secondary" type="button" data-bs-toggle="menu">
Menu
</button>
<div class="menu">
<a class="menu-item" href="#">Action</a>
<a class="menu-item" href="#">Another action</a>
<a class="menu-item" href="#">Something else here</a>
</div>
</div>
</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="invokerDrawer" command="show-modal">
Open drawer
</button>
<dialog class="drawer drawer-start" tabindex="-1" id="invokerDrawer" aria-labelledby="invokerDrawerLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="invokerDrawerLabel">Invoker Commands</h5>
<button type="button" class="btn-close" commandfor="invokerDrawer" command="close" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>This drawer opens with <code>command="show-modal"</code> and closes with <code>command="close"</code>. No Bootstrap JavaScript is involved.</p>
</div>
</dialog>页面滚动
当抽屉以模态方式打开时,<body> 元素的滚动被禁用。使用 data-bs-scroll="true" 与 data-bs-backdrop="false" 可以保持页面滚动并以非模态方式打开抽屉。焦点会移入抽屉,但不会被限制,因此页面仍然可以交互。
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerScrolling" aria-controls="drawerScrolling">Enable body scrolling</button>
<dialog class="drawer drawer-start" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="drawerScrolling" aria-labelledby="drawerScrollingLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerScrollingLabel">Drawer with body scrolling</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>Try scrolling the rest of the page to see this option in action.</p>
</div>
</dialog>页面滚动与背景
你也可以允许 <body> 在保留背景的同时滚动。只要有背景,抽屉就保持模态(showModal() 甚至在……时也会捕获焦点 scroll 是 true.
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerWithBothOptions" aria-controls="drawerWithBothOptions">Enable both scrolling & backdrop</button>
<dialog class="drawer drawer-start" data-bs-scroll="true" tabindex="-1" id="drawerWithBothOptions" aria-labelledby="drawerWithBothOptionsLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerWithBothOptionsLabel">Backdrop with scrolling</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>Try scrolling the rest of the page to see this option in action.</p>
</div>
</dialog>静态背景
当背景设置为静态时,点击抽屉外部不会关闭抽屉。
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#staticBackdrop" aria-controls="staticBackdrop">
Toggle static drawer
</button>
<dialog class="drawer drawer-start" data-bs-backdrop="static" tabindex="-1" id="staticBackdrop" aria-labelledby="staticBackdropLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="staticBackdropLabel">Drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<div>
I will not close if you click outside of me.
</div>
</div>
</dialog>即时抽屉
默认情况下,抽屉在打开和关闭时会有滑动动画。要禁用动画,请添加 .drawer-instant 到 <dialog> 元素。
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#instantDrawer" aria-controls="instantDrawer">
Toggle instant drawer
</button>
<dialog class="drawer drawer-start drawer-instant" tabindex="-1" id="instantDrawer" aria-labelledby="instantDrawerLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="instantDrawerLabel">Instant drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>This drawer doesn’t animate and appears instantly on open and close.</p>
</div>
</dialog>深色抽屉
更改带有工具类的抽屉的外观,以便更好地将它们与不同的上下文(例如深色导航栏)匹配。在这里我们添加 data-bs-theme="dark" 到 .drawer,并且它使其中的所有嵌套元素使用暗模式。
<dialog class="drawer drawer-start show" open tabindex="-1" id="drawerDark" aria-labelledby="drawerDarkLabel" data-bs-theme="dark">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerDarkLabel">Drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>Place drawer content here.</p>
</div>
</dialog>半透明抽屉
在抽屉面板中添加.drawer-translucent以模糊和饱和背景。这会使面板半透明,从而让其背后的内容显示出来。
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerTranslucent" aria-controls="drawerTranslucent">
Toggle translucent drawer
</button>
<dialog class="drawer drawer-start drawer-translucent" tabindex="-1" id="drawerTranslucent" aria-labelledby="drawerTranslucentLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerTranslucentLabel">Translucent drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
Content for the translucent drawer goes here. The background blurs and saturates whatever is behind it.
</div>
</dialog>表格
将 .drawer-sheet 添加到面板,使其与视口边缘对齐。表单变体会去除抽屉的内边距、边框、边框半径和盒子阴影,因此它可以像传统的漂浮式抽屉一样从边缘到边缘显示。它适用于任何位置。
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerSheet" aria-controls="drawerSheet">
Toggle sheet drawer
</button>
<dialog class="drawer drawer-bottom drawer-sheet" tabindex="-1" id="drawerSheet" aria-labelledby="drawerSheetLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerSheetLabel">Sheet drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
Content for the sheet drawer goes here. It sits flush to the edge with no inset, border, rounded corners, or shadow.
</div>
</dialog>响应式
响应式抽屉类会在指定的断点及以下隐藏视口外的内容。在该断点以上,内部内容将照常显示。例如,.lg:drawer 会在 lg 断点以下隐藏抽屉中的内容,但在 lg 断点以上显示该内容。每个断点都有可用的响应式抽屉类。
要制作响应式抽屉,将.drawer基础类替换为响应式变体。抽屉内的关闭按钮无需显式data-bs-target即可工作。
调整浏览器大小以显示响应式抽屉切换按钮。
<button class="btn-solid theme-primary lg:d-none" type="button" data-bs-toggle="drawer" data-bs-target="#drawerResponsive" aria-controls="drawerResponsive">Toggle drawer</button>
<div class="alert theme-info d-none lg:d-block mb-3"><p>Resize your browser to show the responsive drawer toggle.</p></div>
<dialog class="lg:drawer drawer-end" tabindex="-1" id="drawerResponsive" aria-labelledby="drawerResponsiveLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerResponsiveLabel">Responsive drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p class="mb-0">This is content within an <code>.lg:drawer</code>.</p>
</div>
</dialog>职位安排
抽屉组件没有默认位置,因此你必须添加下面的一个修饰类。
.drawer-start将抽屉放置在视口的左侧(如上所示).drawer-end将抽屉放置在视口的右侧.drawer-top将抽屉放置在视口的顶部.drawer-bottom将抽屉放置在视口的底部.drawer-fullscreen覆盖整个视口
在下面尝试顶部、右侧、底部和全屏示例。
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerTop" aria-controls="drawerTop">Toggle top drawer</button>
<dialog class="drawer drawer-top" tabindex="-1" id="drawerTop" aria-labelledby="drawerTopLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerTopLabel">Drawer top</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
...
</div>
</dialog><button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerRight" aria-controls="drawerRight">Toggle right drawer</button>
<dialog class="drawer drawer-end" tabindex="-1" id="drawerRight" aria-labelledby="drawerRightLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerRightLabel">Drawer right</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
...
</div>
</dialog><button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerBottom" aria-controls="drawerBottom">Toggle bottom drawer</button>
<dialog class="drawer drawer-bottom" tabindex="-1" id="drawerBottom" aria-labelledby="drawerBottomLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerBottomLabel">Drawer bottom</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body small">
...
</div>
</dialog><button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerFullscreen" aria-controls="drawerFullscreen">Toggle fullscreen drawer</button>
<dialog class="drawer drawer-fullscreen" tabindex="-1" id="drawerFullscreen" aria-labelledby="drawerFullscreenLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerFullscreenLabel">Fullscreen drawer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>This drawer covers the entire viewport, useful for full-page menus or modal-like experiences.</p>
</div>
</dialog>页脚
在抽屉底部为操作按钮或其他内容添加一个可选的 .drawer-footer。
<dialog class="drawer drawer-start show" open tabindex="-1" id="drawerFooter" aria-labelledby="drawerFooterLabel">
<div class="drawer-header">
<h5 class="drawer-title" id="drawerFooterLabel">Drawer with footer</h5>
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>
</div>
<div class="drawer-body">
<p>Content for the drawer goes here. The footer will stick to the bottom.</p>
</div>
<div class="drawer-footer">
<button type="button" class="btn-solid theme-secondary" data-bs-dismiss="drawer">Close</button>
<button type="button" class="btn-solid theme-primary">Save changes</button>
</div>
</dialog>无障碍访问
由于抽屉是本地 <dialog>,它获得了正确的 dialog 角色。模态抽屉还从 showModal() 获取模态语义和焦点限制。非模态抽屉(scroll: true 和 backdrop: false)使用 show() ,因此它们不会限制焦点或将页面的其余部分标记为不可交互。添加指向抽屉标题的 aria-labelledby 。
CSS
变量
抽屉在.drawer上使用本地 CSS 变量进行实时定制。CSS 变量的值是从每个组件独有的 Sass map生成,并应用于上述类。
// stylelint-disable-next-line scss/dollar-variable-default
$drawer-tokens: defaults(
(
--drawer-inset: var(--spacer),
--drawer-zindex: var(--z-drawer),
--drawer-width: 400px,
--drawer-height: 30vh,
--drawer-padding-x: var(--spacer),
--drawer-padding-y: var(--spacer),
--drawer-color: var(--fg-body),
--drawer-bg: var(--bg-body),
--drawer-border-width: var(--border-width),
--drawer-border-color: var(--border-color-translucent),
--drawer-border-radius: var(--radius-7),
--drawer-box-shadow: var(--box-shadow-xl),
--drawer-transition-property: "transform, visibility",
--drawer-transition-duration: .3s,
--drawer-transition-timing: var(--transition-timing-overlay),
--drawer-title-line-height: 1.5,
--drawer-backdrop-bg: color-mix(in oklch, var(--bg-body) 25%, transparent),
--drawer-backdrop-blur: 8px,
),
$drawer-tokens
);
抽屉背景的令牌可以在单独的映射中获得,因为它们为原生 ::backdrop 伪元素设置样式。
// stylelint-disable-next-line scss/dollar-variable-default
$drawer-backdrop-tokens: defaults(
(
--drawer-backdrop-bg: var(--bg-body),
--drawer-backdrop-opacity: 25%,
--drawer-backdrop-blur: 8px,
),
$drawer-backdrop-tokens
);
用法
抽屉插件是基于原生<dialog>元素构建的,并使用一些类和属性来处理繁重的工作:
.drawer在一个<dialog>元素启用抽屉行为.drawer-start将抽屉放在左边.drawer-end将抽屉放在右边.drawer-top将抽屉放在顶部.drawer-bottom将抽屉放在底部
添加一个带有 data-bs-dismiss="drawer" 属性的关闭按钮,该按钮会触发 JavaScript 功能。确保与之一起使用 <button> 元素,以确保在所有设备上的正常行为。
通过数据属性
| 属性 | 描述 |
|---|---|
data-bs-toggle="drawer" | 在触发元素上初始化抽屉行为。 |
data-bs-target | 用于打开<dialog>抽屉元素的CSS选择器(或在链接上使用href)。 |
data-bs-dismiss="drawer" | 在关闭控件上激活时,关闭抽屉。 |
切换
添加 data-bs-toggle="drawer" 和一个 data-bs-target 或 href 到元素以自动分配一个抽屉元素的控制。 data-bs-target attribute 接受一个 CSS 选择器来应用抽屉。请确保使用一个 <dialog> 具有该类的元素 drawer.
解雇
解雇可以通过 data-bs-dismiss 按钮上的属性 在抽屉里 如下所示:
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="关闭"></button>或者在抽屉外部的按钮上使用额外的 data-bs-target,如下所示:
<button type="button" class="btn-close" data-bs-dismiss="drawer" data-bs-target="#my-drawer" aria-label="关闭"></button>虽然两种关闭抽屉的方式都被支持,但请记住,从抽屉外部关闭抽屉并不符合 ARIA 编写实践指南对话框(模态)模式。请自行承担风险。
通过 JavaScript
手动启用:
const drawerElementList = document.querySelectorAll('dialog.drawer')
const drawerList = [...drawerElementList].map(drawerEl => new bootstrap.Drawer(drawerEl))
依赖项
如果你从源代码构建 Bootstrap 的 JS,抽屉插件需要以下 JavaScript 文件:
| 文件 | 描述 |
|---|---|
js/src/drawer.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 | 核心实用功能 |
js/src/util/swipe.ts | 滑动手势工具 |
选项
由于选项可以通过数据属性或 JavaScript 传递,你可以将选项名称附加到 data-bs-,就像在 data-bs-animation="{value}" 中一样。确保在通过数据属性传递选项时,将选项名称的大小写类型从“camelCase”更改为“kebab-case”。例如,使用 data-bs-custom-class="beautifier" 而不是 data-bs-customClass="beautifier"。
所有组件都支持一个保留的数据属性 data-bs-config,该属性可以以 JSON 字符串的形式存放简单的组件配置。当一个元素具有 data-bs-config='{"delay":0, "title":123}' 和 data-bs-title="456" 属性时,最终的 title 值将是 456,并且单独的数据属性将覆盖在 data-bs-config 上给定的值。此外,现有的数据属性也可以存放像 data-bs-delay='{"show":0,"hide":150}' 这样的 JSON 值。
最终的配置对象是data-bs-config、data-bs-和js object合并的结果,其中最新提供的键值会覆盖其他键值。
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
backdrop | 布尔值或字符串 static | true | 在抽屉打开时在页面主体上应用背景。或者,指定 static 用于点击时不会关闭抽屉的背景。 |
keyboard | boolean | true | 按下 Esc 键时关闭抽屉。 |
scroll | boolean | false | 在抽屉打开时允许页面主体滚动。与 backdrop: false 结合,表示以非模态方式打开抽屉(无焦点陷阱)。 |
方法
显示或隐藏组件的方法会返回一个 Promise。 当过渡结束时,该 Promise 会被解析,所以 await 会在 shown.bs.* 或 hidden.bs.* 监听器运行的同一时刻继续。方法仍会立即返回,并且永远不会阻塞调用者。对已在过渡中的组件进行调用不会有任何效果,并会立即解析。在我们的 JavaScript 文档中了解更多。
将你的内容激活为抽屉元素。可接受一个可选的选项 object。
你可以使用构造函数创建一个抽屉实例,例如:
const bsDrawer = new bootstrap.Drawer('#myDrawer')
| 方法 | 描述 |
|---|---|
dispose | 销毁元素的抽屉。 |
getInstance | 静态 一种方法,允许你获取与 DOM 元素关联的抽屉实例。 |
getOrCreateInstance | 静态 该方法允许你获取与 DOM 元素关联的抽屉实例,或者在尚未初始化的情况下创建一个新的实例。 |
hide | 隐藏一个抽屉元素。 返回一个在抽屉元素被隐藏后解析的 Promise (即在……之后 hidden.bs.drawer 事件触发)。 |
show | 显示一个抽屉元素。 返回一个在抽屉元素显示后解析的 Promise (即在……之后 shown.bs.drawer 事件触发)。 |
toggle | 切换抽屉元素显示或隐藏。 返回一个在抽屉元素显示或隐藏后解析的承诺 (即在……之后 shown.bs.drawer 或 hidden.bs.drawer 事件触发)。 |
事件
Bootstrap 的抽屉类提供了一些事件,用于连接抽屉功能。
| 事件类型 | 描述 |
|---|---|
hide.bs.drawer | 当……时,此事件会立即触发 hide 方法已被调用。 |
hidden.bs.drawer | 当抽屉元素被隐藏不再显示给用户时,会触发此事件(会等待 CSS 过渡完成)。 |
hidePrevented.bs.drawer | 当抽屉显示时,将触发此事件,其背景是 static 并且在抽屉外部点击时会触发该事件。当按下退出键时也会触发该事件,并且 keyboard 选项设置为 false. |
show.bs.drawer | 当...时,此事件会立即触发 show 实例方法被调用。 |
shown.bs.drawer | 当抽屉元素对用户可见时会触发此事件(将等待 CSS 过渡完成)。 |
const myDrawer = document.getElementById('myDrawer')
myDrawer.addEventListener('hidden.bs.drawer', event => {
// do something...
})