JS 组件
好奇哪些组件明确需要我们的 JavaScript 和 Floating UI 或 Vanilla Calendar Pro?
- 解散的警报
- 用于切换状态和复选框/单选按钮功能的按钮
- 适用于所有幻灯片行为、控件和指示器的轮播
- 折叠以切换内容的可见性
- 用于日期选择的日期选择器(也需要 Vanilla Calendar Pro)
- 对话 用于显示、定位和滚动行为
- 用于显示和定位的菜单(也需要 浮动界面)
- 用于扩展我们的 Collapse 和 Drawer 插件以实现响应式行为的导航栏
- 导航 用于导航标记和样式; 标签 用于切换标签窗格的插件
- 用于显示、定位和滚动行为的抽屉
- 用于滚动行为和导航更新的滚动监听
- 用于显示和消失的提示
- 用于显示和定位的工具提示和弹出框(也需要 Floating UI)
个人或编译
插件可以单独包含(使用 Bootstrap 的单独 js/dist/*.js),或者使用 bootstrap.js 或压缩的 bootstrap.min.js 一次性全部包含(不要同时包含两者)。
如果你使用打包工具(Webpack、Parcel、Vite…),你可以只导入你需要的插件,你的打包工具会自动去除其余部分:
import { Toast, Tooltip } from 'bootstrap'
TypeScript
Bootstrap 的插件是用 TypeScript 编写的,并附带内置类型声明——不需要 @types/bootstrap 包。主入口点以及 js/dist/*.js 下的每个单独插件都是完全类型化的,包括每个插件的配置选项:
import { Tooltip } from 'bootstrap'
const tooltip = Tooltip.getOrCreateInstance('#example')
tooltip.show()
每个插件模块也会导出其配置对象类型(例如 TooltipConfig),如果你需要为自己的包装器进行类型定义。
与 JavaScript 框架的使用
虽然 Bootstrap CSS 可以与任何框架一起使用,但 Bootstrap JavaScript 并不完全兼容像 React、Vue 和 Angular 这样的 JavaScript 框架,这些框架假设对 DOM 有完全的了解。Bootstrap 和框架都可能尝试修改同一个 DOM 元素,从而导致菜单卡在“打开”状态等错误。
对于使用这种类型框架的人来说,更好的选择是使用特定于框架的包 而不是 Bootstrap 的 JavaScript。以下是一些最受欢迎的选项:
- React: React Bootstrap(Bootstrap 5)
- Vue 3: BootstrapVueNext(Bootstrap 5)
- Angular: ng-bootstrap(Bootstrap 5)或 ngx-bootstrap(Bootstrap 5)
将 Bootstrap 作为模块使用
自己试一试! 从 twbs/examples 仓库 下载使用 Bootstrap 作为 ES 模块的源代码和工作演示。
Bootstrap 的 JavaScript 是作为原生 ES 模块构建的(bootstrap.js 和 bootstrap.min.js)。使用 <script type="module"> 在浏览器中加载 Bootstrap:
<script type="module">
import { Toast } from './bootstrap.min.js'
Array.from(document.querySelectorAll('.toast'))
.forEach(toastNode => new Toast(toastNode))
</script>
在浏览器中使用 ESM 需要完整路径或一个 导入地图 对于像这样的裸模块说明符 @floating-ui/dom 和 vanilla-calendar-pro这是一个使用导入映射的完整示例:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@6.0.0-alpha.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-B/GM4XqrwHnWXNOWMbloTmrYXZg10cakYGmpfsR/bbzQ6JAJI4ihuyADKLnBgrCe" crossorigin="anonymous">
<title>Hello, modularity!</title>
</head>
<body>
<h1>Hello, modularity!</h1>
<button id="popoverButton" type="button" class="btn-solid theme-primary btn-lg" data-bs-toggle="popover" title="ESM in Browser" data-bs-content="Bang!">Custom popover</button>
<script type="importmap">
{
"imports": {
"@floating-ui/dom": "https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.7.6/dist/floating-ui.dom.esm.min.js",
"vanilla-calendar-pro": "https://cdn.jsdelivr.net/npm/vanilla-calendar-pro@3.4.0/index.mjs",
"bootstrap": "https://cdn.jsdelivr.net/npm/bootstrap@6.0.0-alpha.1/dist/js/bootstrap.min.js"
}
}
</script>
<script type="module">
import * as bootstrap from 'bootstrap'
new bootstrap.Popover(document.getElementById('popoverButton'))
</script>
</body>
</html>
不依赖 Floating UI 的组件(如 Toast、Alert、Collapse 等)可以单独导入,无需任何导入映射:
<script type="module">
import Toast from './js/dist/toast.js'
Array.from(document.querySelectorAll('.toast'))
.forEach(toastNode => new Toast(toastNode))
</script>
依赖
一些插件和 CSS 组件依赖于其他插件。如果你单独包含插件,请确保在文档中检查这些依赖关系。
我们的菜单、弹出层和工具提示也依赖于 Floating UI。我们的日期选择器也依赖于 Vanilla Calendar Pro。
数据属性
几乎所有的 Bootstrap 插件都可以仅通过 HTML 使用数据属性启用和配置(这是我们首选的使用 JavaScript 功能的方式)。请确保 在单个元素上只使用一组数据属性(例如,不能通过同一个按钮触发工具提示和对话框)。
由于选项可以通过数据属性或 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合并的结果,其中最新提供的键值会覆盖其他键值。
选择器
出于性能原因,我们使用原生的 querySelector 和 querySelectorAll 方法查询 DOM 元素,因此你必须使用有效选择器。如果你使用像 collapse:Example 这样的特殊选择器,请确保对它们进行转义。
事件
Bootstrap 为大多数插件的独特操作提供自定义事件。通常,这些事件有不定式和过去分词形式 —— 不定式(例如 show)在事件开始时触发,而过去分词形式(例如 shown)在操作完成时触发。
所有不定事件都提供 preventDefault() 功能。这提供了在动作开始之前停止其执行的能力。从事件处理程序中返回 false 也会自动调用 preventDefault()。
const myDialogEl = document.querySelector('#myDialog')
myDialogEl.addEventListener('show.bs.dialog', event => {
return event.preventDefault() // stops dialog from being shown
})
编程 API
所有构造函数都接受一个可选的 options 对象或不传参数(此时插件将以其默认行为初始化):
const myDialogEl = document.querySelector('#myDialog')
const dialog = new bootstrap.Dialog(myDialogEl) // initialized with defaults
const configObject = { keyboard: false }
const dialog1 = new bootstrap.Dialog(myDialogEl, configObject) // initialized with no keyboard
如果你想获取一个特定的插件实例,每个插件都会提供一个 getInstance 方法。例如,直接从一个元素中检索实例:
bootstrap.Popover.getInstance(myPopoverEl)
如果实例未在请求的元素上初始化,则此方法将返回null。
或者,可以使用 getOrCreateInstance 来获取与 DOM 元素关联的实例,或者在尚未初始化的情况下创建一个新的实例。
bootstrap.Popover.getOrCreateInstance(myPopoverEl, configObject)
如果实例未被初始化,它可能会接受并使用作为第二个参数的可选配置对象。
构造函数中的 CSS 选择器
除了getInstance和getOrCreateInstance方法外,所有插件构造函数都可以接受一个 DOM 元素或一个有效的CSS 选择器作为第一个参数。插件元素通过querySelector方法找到,因为我们的插件只支持单个元素。
const dialog = new bootstrap.Dialog('#myDialog')
const menu = new bootstrap.Menu('[data-bs-toggle="menu"]')
const drawer = bootstrap.Drawer.getInstance('#myDrawer')
const alert = bootstrap.Alert.getOrCreateInstance('#myAlert')
承诺与过渡
所有编程 API 方法都是 异步 的,并在转换开始后 但在其结束之前 返回给调用者。
显示或隐藏组件的方法会返回一个 promise。当过渡结束时,promise 会被解决,所以你可以 await 该方法,而不是监听事件。
const collapse = bootstrap.Collapse.getOrCreateInstance('#myCollapse')
await collapse.show()
// The collapsible area is now expanded
这些方法返回一个 promise:
| 方法 | 组件 |
|---|---|
show, hide, toggle | 折叠面板, 下拉组合框, 日期选择器, 对话框, 抽屉, 菜单, 弹出框, 提示工具 |
show, hide | 消息提示 |
show | 标签页 |
close | 警告 |
该 Promise 以无值方式完成。它在匹配的 shown.bs.*、hidden.bs.* 或 closed.bs.* 事件触发的同一时刻完成,因此两种方式都会同时运行你的代码。当你必须响应每一次变化,包括那些你的代码没有引发的变化时,请使用该事件。
const myDrawerEl = document.querySelector('#myDrawer')
const drawer = bootstrap.Drawer.getOrCreateInstance(myDrawerEl)
// Await the method you called…
await drawer.hide()
saveState()
// …or listen for every hide, whoever started it
myDrawerEl.addEventListener('hidden.bs.drawer', () => {
saveState()
})
因为每个方法都会返回一个 promise,你可以按顺序运行步骤,而无需嵌套监听器。
const dialog = bootstrap.Dialog.getOrCreateInstance('#myDialog')
const toast = bootstrap.Toast.getOrCreateInstance('#myToast')
await dialog.hide()
await toast.show()
当调用什么也不做时——例如当组件已经打开,或当监听器调用时——这个承诺也会被解决 preventDefault() 在……上 show.bs.* 事件,或当你在过渡过程中销毁组件时。 await 因此它永远不会挂起,但它也不会告诉你状态是否发生了变化。当状态重要时,请自己检查状态。
此外,对 正在过渡的组件的调用方法将被忽略。对于上述返回 promise 的方法,这种调用会立即解析。它不会等待正在运行的过渡结束。
const myCarouselEl = document.querySelector('#myCarousel')
const carousel = bootstrap.Carousel.getInstance(myCarouselEl) // Retrieve a Carousel instance
myCarouselEl.addEventListener('slid.bs.carousel', event => {
carousel.to('2') // Will slide to the slide 2 as soon as the transition to slide 1 is finished
})
carousel.to('1') // Will start sliding to the slide 1 and returns to the caller
carousel.to('2') // !! Will be ignored, as the transition to the slide 1 is not finished !!
dispose 方法
请勿呼叫 dispose 紧接着 hide()此时隐藏过渡仍在进行中,因此组件会在过渡中途被销毁。请先等待该承诺:
const toast = bootstrap.Toast.getInstance('#myToast')
await toast.hide()
toast.dispose()
基于事件的等效方法也可以使用:
const myToastEl = document.querySelector('#myToast')
const toast = bootstrap.Toast.getInstance(myToastEl)
myToastEl.addEventListener('hidden.bs.toast', () => {
toast.dispose()
})
toast.hide()
默认设置
你可以通过修改插件的Constructor.Default对象来更改插件的默认设置:
// changes default for the toast plugin's `autohide` option to false
bootstrap.Toast.Default.autohide = false
方法和属性
每个 Bootstrap 插件都提供以下方法和静态属性。
| 方法 | 描述 |
|---|---|
dispose | 销毁元素的插件实例。(移除DOM元素上存储的数据) |
getInstance | 静态方法,可获取与DOM元素关联的插件实例。 |
getOrCreateInstance | 静态方法,可获取与DOM元素关联的插件实例,如果尚未初始化,则创建一个新的实例。 |
| 静态属性 | 描述 |
|---|---|
NAME | 返回插件名称。(例如:bootstrap.Tooltip.NAME) |
VERSION | 可以通过插件构造函数的 VERSION 属性访问每个 Bootstrap 插件的版本。(例如:bootstrap.Tooltip.VERSION) |
消毒剂
一些 JavaScript 组件可以在其配置中呈现或接受任意 HTML。为了防止跨站脚本(XSS)攻击,这些组件在将任何接受 HTML 的选项呈现到页面之前,会使用我们内置的内容清理器对其进行清理。内容清理默认是启用的。具体来说:
- 如果配置为这样做,弹出框和工具提示可以将任意 HTML 渲染到页面上。
- 芯片和导航溢出可以为它们的图标选项(
dismissIcon、moreIcon和[data-bs-overflow-icon])接受 HTML。
默认情况下,工具提示和弹出框内容允许的标签和属性如下。任何未明确允许的标签或属性在清理过程中都会被移除:
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
export const DefaultAllowlist: SanitizerAllowList = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
area: [],
b: [],
br: [],
col: [],
code: [],
dd: [],
div: [],
dl: [],
dt: [],
em: [],
hr: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
i: [],
img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
li: [],
ol: [],
p: [],
pre: [],
s: [],
small: [],
span: [],
sub: [],
sup: [],
strong: [],
u: [],
ul: []
}
图标选项使用一个独立的、更严格的允许列表,涵盖默认的 SVG 图标和常见的内联图标标记:
/**
* Allowlist for icon HTML options (Chips `dismissIcon`, NavOverflow `moreIcon`,
* and markup supplied via `[data-bs-overflow-icon]`). Covers the default SVG
* icons plus common inline-icon markup. Event-handler attributes and tags not
* listed here are stripped by `sanitizeHtml`.
*/
export const DefaultIconAllowlist: SanitizerAllowList = {
'*': ['class', 'role', ARIA_ATTRIBUTE_PATTERN],
// Attribute names are matched lowercased (see allowedAttribute). `viewBox` is
// listed as `viewbox` so the default SVG icons keep their coordinate system.
svg: ['xmlns', 'width', 'height', 'viewbox', 'fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'focusable'],
path: ['d', 'fill', 'stroke', 'stroke-width', 'fill-rule', 'clip-rule'],
line: ['x1', 'y1', 'x2', 'y2', 'stroke', 'stroke-width', 'stroke-linecap'],
circle: ['cx', 'cy', 'r', 'fill', 'stroke', 'stroke-width'],
rect: ['x', 'y', 'width', 'height', 'rx', 'ry', 'fill', 'stroke', 'stroke-width'],
polyline: ['points', 'fill', 'stroke', 'stroke-width'],
polygon: ['points', 'fill', 'stroke', 'stroke-width'],
g: ['fill', 'stroke', 'stroke-width', 'transform'],
// No `use` here: `href` / `xlink:href` on <use> can load external SVG
// fragments. Apps that need sprites can extend this allowlist deliberately.
span: [],
i: []
}
使用这些高级选项时请小心。更多信息请参考 OWASP 的跨站脚本预防备忘单。仅因禁用或修改内容消毒而造成的漏洞不被视为 Bootstrap 安全模型的涵盖范围。
你可以向此默认 allowList 添加新值:
const myDefaultAllowList = bootstrap.Tooltip.Default.allowList
// To allow table elements
myDefaultAllowList.table = []
// To allow td elements and data-bs-option attributes on td elements
myDefaultAllowList.td = ['data-bs-option']
// You can push your custom regex to validate your attributes.
// Be careful about your regular expressions being too lax
const myCustomRegex = /^data-my-app-[\w-]+/
myDefaultAllowList['*'].push(myCustomRegex)
你也可以用专门的库替换我们的消毒器,例如 DOMPurify:
const myTooltipEl = document.querySelector('#myTooltip')
const tooltip = new bootstrap.Tooltip(myTooltipEl, {
sanitizeFn(content) {
return DOMPurify.sanitize(content)
}
})
已禁用 JavaScript
Bootstrap 的插件在 JavaScript 被禁用时没有特殊的回退方案。如果你在意这种情况下的用户体验,可以使用 <noscript> 向你的用户解释情况(以及如何重新启用 JavaScript),和/或添加你自己的自定义回退方案。