如何将Bootstrap组件保存为独立可运行的代码片段?
获取Bootstrap单个组件的独立CSS/JS代码方法
如果你不想引入完整的Bootstrap CSS和JS文件,只想提取单个组件对应的样式和脚本代码嵌入页面,有以下几种可行方法:
官方自定义构建工具(最靠谱)
Bootstrap官网提供了自定义构建功能,你可以只勾选需要的组件(比如Accordion),工具会自动处理组件依赖,生成仅包含该组件相关代码的CSS和JS文件。下载后把代码分别复制到页面的<style>和<script>标签里,再加上组件HTML即可。
操作要点:取消默认全选,只选目标组件,工具会自动勾选它依赖的基础模块(比如Accordion依赖Collapse组件),构建完成后下载压缩包,解压后拿到对应的代码文件。从源码手动提取
Bootstrap的源码是模块化的,可直接从GitHub仓库找到对应组件的SCSS和JS文件:- CSS部分:找到组件对应的SCSS文件(如
scss/_accordion.scss),用在线SCSS编译工具把它和依赖的基础变量、混合宏一起编译成CSS; - JS部分:找到组件的JS源文件(如
js/src/accordion.js),复制代码的同时要一并复制它依赖的基础模块(比如BaseComponent、Collapse的代码),否则组件会无法正常工作。
- CSS部分:找到组件对应的SCSS文件(如
第三方在线提取工具
有一些在线工具支持输入Bootstrap组件HTML,自动提取对应的CSS和JS代码,但要注意工具的可靠性,避免拿到冗余或错误的代码。
示例:Accordion组件完整嵌入代码
<style> /* Accordion组件相关CSS代码 */ .accordion { --bs-accordion-color: #212529; --bs-accordion-bg: #fff; --bs-accordion-border-color: rgba(0, 0, 0, 0.125); --bs-accordion-border-width: 1px; --bs-accordion-border-radius: 0.375rem; --bs-accordion-inner-border-radius: calc(0.375rem - 1px); --bs-accordion-btn-padding-x: 1.25rem; --bs-accordion-btn-padding-y: 1rem; --bs-accordion-btn-color: #212529; --bs-accordion-btn-bg: var(--bs-accordion-bg); --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); --bs-accordion-btn-icon-width: 1.25rem; --bs-accordion-btn-icon-transform: rotate(-180deg); --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230a58ca'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); --bs-accordion-body-padding-x: 1.25rem; --bs-accordion-body-padding-y: 1rem; --bs-accordion-active-color: #0a58ca; --bs-accordion-active-bg: #e7f5ff; } .accordion-item { border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color); } .accordion-item:first-of-type { border-top-left-radius: var(--bs-accordion-border-radius); border-top-right-radius: var(--bs-accordion-border-radius); } .accordion-item:first-of-type .accordion-button { border-top-left-radius: var(--bs-accordion-inner-border-radius); border-top-right-radius: var(--bs-accordion-inner-border-radius); } .accordion-item:not(:first-of-type) { border-top: 0; } .accordion-item:last-of-type { border-bottom-right-radius: var(--bs-accordion-border-radius); border-bottom-left-radius: var(--bs-accordion-border-radius); } .accordion-item:last-of-type .accordion-button.collapsed { border-bottom-right-radius: var(--bs-accordion-inner-border-radius); border-bottom-left-radius: var(--bs-accordion-inner-border-radius); } .accordion-item:last-of-type .accordion-collapse { border-bottom-right-radius: var(--bs-accordion-border-radius); border-bottom-left-radius: var(--bs-accordion-border-radius); } .accordion-button { position: relative; display: flex; align-items: center; width: 100%; padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x); font-size: 1rem; color: var(--bs-accordion-btn-color); text-align: left; background-color: var(--bs-accordion-btn-bg); border: 0; border-radius: 0; overflow-anchor: none; transition: var(--bs-accordion-btn-icon-transition); } @media (prefers-reduced-motion: reduce) { .accordion-button { transition: none; } } .accordion-button:not(.collapsed) { color: var(--bs-accordion-active-color); background-color: var(--bs-accordion-active-bg); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.125); } .accordion-button:not(.collapsed)::after { background-image: var(--bs-accordion-btn-active-icon); transform: var(--bs-accordion-btn-icon-transform); } .accordion-button::after { flex-shrink: 0; width: var(--bs-accordion-btn-icon-width); height: var(--bs-accordion-btn-icon-width); margin-left: auto; content: ""; background-image: var(--bs-accordion-btn-icon); background-repeat: no-repeat; background-size: var(--bs-accordion-btn-icon-width); transition: var(--bs-accordion-btn-icon-transition); } @media (prefers-reduced-motion: reduce) { .accordion-button::after { transition: none; } } .accordion-button:hover { z-index: 2; } .accordion-button:focus { z-index: 3; border-color: var(--bs-accordion-btn-focus-border-color); outline: 0; box-shadow: var(--bs-accordion-btn-focus-box-shadow); } .accordion-collapse { flex: 1 1 auto; } .accordion-body { padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x); } </style> <script> // Accordion组件依赖的基础模块及自身代码 class BaseComponent { constructor(element, config) { element = typeof element === 'string' ? document.querySelector(element) : element if (!element) { return } this._element = element this._config = this._getConfig(config) } _getConfig(config) { const dataAttributes = this._getConfigFromDataAttributes() return { ...this.constructor.Default, ...dataAttributes, ...typeof config === 'object' ? config : {} } } _getConfigFromDataAttributes() { const attributes = {} const dataset = this._element.dataset for (const key in dataset) { if (key.startsWith('bs')) { let camelCaseKey = key.replace(/^bs([A-Z])/, (match, p1) => p1.toLowerCase()) camelCaseKey = camelCaseKey.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`) try { attributes[camelCaseKey] = JSON.parse(dataset[key]) } catch (e) { attributes[camelCaseKey] = dataset[key] } } } return attributes } static getInstance(element) { return element[`_${this.NAME}`] } static getOrCreateInstance(element, config = {}) { let instance = this.getInstance(element) if (!instance) { instance = new this(element, config) } return instance } } class Collapse extends BaseComponent { static get Default() { return { toggle: true, parent: null } } static get NAME() { return 'collapse' } constructor(element, config) { super(element, config) this._isTransitioning = false this._triggerArray = [] this._initializeChildren() if (this._config.toggle) { this.toggle() } } toggle() { if (this._element.classList.contains('show')) { this.hide() } else { this.show() } } show() { if (this._isTransitioning || this._element.classList.contains('show')) { return } let parent = this._config.parent ? this._getParent() : null if (parent) { const children = parent.querySelectorAll('.collapse.show, .collapsing') for (const child of children) { if (child !== this._element) { const instance = Collapse.getOrCreateInstance(child) instance.hide() } } } const startEvent = new Event('show.bs.collapse') this._element.dispatchEvent(startEvent) if (startEvent.defaultPrevented) { return } this._element.classList.add('collapsing') this._element.classList.remove('collapse', 'show') this._isTransitioning = true const complete = () => { this._isTransitioning = false this._element.classList.remove('collapsing') this._element.classList.add('collapse', 'show') const shownEvent = new Event('shown.bs.collapse') this._element.dispatchEvent(shownEvent) } const height = this._element.scrollHeight this._element.style.height = `${height}px` this._element.addEventListener('transitionend', complete, { once: true }) } hide() { if (this._isTransitioning || !this._element.classList.contains('show')) { return } const startEvent = new Event('hide.bs.collapse') this._element.dispatchEvent(startEvent) if (startEvent.defaultPrevented) { return } this._element.classList.add('collapsing') this._element.classList.remove('collapse', 'show') this._isTransitioning = true const complete = () => { this._isTransitioning = false this._element.classList.remove('collapsing') this._element.classList.add('collapse') const hiddenEvent = new Event('hidden.bs.collapse') this._element.dispatchEvent(hiddenEvent) } const height = this._element.scrollHeight this._element.style.height = `${height}px` requestAnimationFrame(() => { this._element.style.height = '0' }) this._element.addEventListener('transitionend', complete, { once: true }) } _getParent() { const parent = document.querySelector(this._config.parent) if (!parent) { return null } return parent } _initializeChildren() { const triggers = document.querySelectorAll(`[data-bs-toggle="collapse"][data-bs-target="#${this._element.id}"]`) this._triggerArray = Array.from(triggers) } } class Accordion extends Collapse { static get Default() { return { ...super.Default, rootElement: '.accordion' }; } static get NAME() { return 'accordion'; } constructor(element, config) { super(element, config); this._parent = this._getRootElement() } toggle() { if (this._element.classList.contains('collapsed')) { this._parent.querySelectorAll('.accordion-button').forEach(button => { if (button !== this._element && !button.classList.contains('collapsed')) { const collapse = Collapse.getOrCreateInstance(button) collapse.hide() } }) } super.toggle() } _getRootElement() { const selector = this._config.rootElement const parent = this._element.closest(selector) if (!parent) { return this._element } return parent } } // 初始化组件 document.querySelectorAll('.accordion-button').forEach(button => { new Accordion(button) }) </script> <div class="accordion" id="accordionExample"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> Accordion Item #1 </button> </h2> <div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#accordionExample"> <div class="accordion-body"> <strong>This is the first item's accordion body.</strong> It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow. </div> </div> </div> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> Accordion Item #2 </button> </h2> <div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#accordionExample"> <div class="accordion-body"> <strong>This is the second item's accordion body.</strong> It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow. </div> </div> </div> </div>
内容的提问来源于stack exchange,提问作者Evgeniy
相关产品推荐
相关产品推荐

