本章概述
Bootstrap 提供了许多高级组件,包括模态框、轮播图、折叠面板、工具提示、弹出框、进度条、列表组等。这些组件能够帮助我们构建更加丰富和交互性强的用户界面。本章将详细介绍这些高级组件的使用方法和自定义技巧。
模态框组件
1. 基础模态框
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap 模态框组件</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container my-5">
<h2 class="text-primary mb-4">模态框组件</h2>
<!-- 触发按钮 -->
<div class="mb-4">
<h5>基础模态框</h5>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#basicModal">
打开基础模态框
</button>
<button type="button" class="btn btn-success ms-2" data-bs-toggle="modal" data-bs-target="#largeModal">
大尺寸模态框
</button>
<button type="button" class="btn btn-warning ms-2" data-bs-toggle="modal" data-bs-target="#smallModal">
小尺寸模态框
</button>
<button type="button" class="btn btn-info ms-2" data-bs-toggle="modal" data-bs-target="#fullscreenModal">
全屏模态框
</button>
</div>
<!-- 基础模态框 -->
<div class="modal fade" id="basicModal" tabindex="-1" aria-labelledby="basicModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="basicModalLabel">基础模态框</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>这是一个基础的模态框示例。您可以在这里放置任何内容,包括文本、表单、图片等。</p>
<p>模态框是一个覆盖在主窗口上的对话框,用于显示重要信息或收集用户输入。</p>
<div class="alert alert-info" role="alert">
<i class="bi bi-info-circle"></i> 这是一个信息提示框,用于显示重要信息。
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary">保存更改</button>
</div>
</div>
</div>
</div>
<!-- 大尺寸模态框 -->
<div class="modal fade" id="largeModal" tabindex="-1" aria-labelledby="largeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="largeModalLabel">大尺寸模态框</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<h6>左侧内容</h6>
<p>这是大尺寸模态框的左侧内容区域。可以放置更多的信息和控件。</p>
<ul>
<li>功能特性 1</li>
<li>功能特性 2</li>
<li>功能特性 3</li>
</ul>
</div>
<div class="col-md-6">
<h6>右侧内容</h6>
<p>这是大尺寸模态框的右侧内容区域。</p>
<div class="mb-3">
<label for="exampleInput" class="form-label">示例输入</label>
<input type="text" class="form-control" id="exampleInput" placeholder="输入内容">
</div>
<div class="mb-3">
<label for="exampleSelect" class="form-label">选择选项</label>
<select class="form-select" id="exampleSelect">
<option selected>选择一个选项</option>
<option value="1">选项 1</option>
<option value="2">选项 2</option>
<option value="3">选项 3</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
<!-- 小尺寸模态框 -->
<div class="modal fade" id="smallModal" tabindex="-1" aria-labelledby="smallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="smallModalLabel">确认操作</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>您确定要执行此操作吗?</p>
<p class="text-muted small">此操作不可撤销。</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-danger btn-sm">确认</button>
</div>
</div>
</div>
</div>
<!-- 全屏模态框 -->
<div class="modal fade" id="fullscreenModal" tabindex="-1" aria-labelledby="fullscreenModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="fullscreenModalLabel">全屏模态框</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
<h6>侧边栏</h6>
<ul class="list-group">
<li class="list-group-item active">首页</li>
<li class="list-group-item">产品</li>
<li class="list-group-item">服务</li>
<li class="list-group-item">关于我们</li>
</ul>
</div>
<div class="col-md-9">
<h6>主要内容区域</h6>
<p>这是全屏模态框的主要内容区域。可以在这里放置复杂的布局和大量的内容。</p>
<div class="row">
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h6 class="card-title">卡片 1</h6>
<p class="card-text">这是第一个卡片的内容。</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h6 class="card-title">卡片 2</h6>
<p class="card-text">这是第二个卡片的内容。</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h6 class="card-title">卡片 3</h6>
<p class="card-text">这是第三个卡片的内容。</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">应用</button>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
2. 高级模态框功能
<!-- 高级模态框功能 -->
<div class="container my-4">
<h2 class="text-primary mb-4">高级模态框功能</h2>
<!-- 触发按钮 -->
<div class="mb-4">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#formModal">
表单模态框
</button>
<button type="button" class="btn btn-success ms-2" data-bs-toggle="modal" data-bs-target="#imageModal">
图片模态框
</button>
<button type="button" class="btn btn-warning ms-2" onclick="showDynamicModal()">
动态模态框
</button>
<button type="button" class="btn btn-info ms-2" data-bs-toggle="modal" data-bs-target="#nestedModal">
嵌套模态框
</button>
</div>
<!-- 表单模态框 -->
<div class="modal fade" id="formModal" tabindex="-1" aria-labelledby="formModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="formModalLabel">用户注册</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form id="registrationForm">
<div class="modal-body">
<div class="mb-3">
<label for="username" class="form-label">用户名 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="username" required>
<div class="invalid-feedback">
请输入用户名
</div>
</div>
<div class="mb-3">
<label for="email" class="form-label">邮箱地址 <span class="text-danger">*</span></label>
<input type="email" class="form-control" id="email" required>
<div class="invalid-feedback">
请输入有效的邮箱地址
</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">密码 <span class="text-danger">*</span></label>
<input type="password" class="form-control" id="password" required>
<div class="invalid-feedback">
密码至少需要6个字符
</div>
</div>
<div class="mb-3">
<label for="confirmPassword" class="form-label">确认密码 <span class="text-danger">*</span></label>
<input type="password" class="form-control" id="confirmPassword" required>
<div class="invalid-feedback">
密码不匹配
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="agreeTerms" required>
<label class="form-check-label" for="agreeTerms">
我同意 <a href="#" class="text-decoration-none">服务条款</a> 和 <a href="#" class="text-decoration-none">隐私政策</a>
</label>
<div class="invalid-feedback">
请同意服务条款
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="submit" class="btn btn-primary">注册</button>
</div>
</form>
</div>
</div>
</div>
<!-- 图片模态框 -->
<div class="modal fade" id="imageModal" tabindex="-1" aria-labelledby="imageModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="imageModalLabel">图片预览</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<img src="https://via.placeholder.com/800x400" class="img-fluid" alt="示例图片">
<div class="mt-3">
<h6>图片信息</h6>
<p class="text-muted">文件名:example-image.jpg</p>
<p class="text-muted">尺寸:800 x 400 像素</p>
<p class="text-muted">大小:125 KB</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">下载</button>
</div>
</div>
</div>
</div>
<!-- 嵌套模态框 -->
<div class="modal fade" id="nestedModal" tabindex="-1" aria-labelledby="nestedModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="nestedModalLabel">第一个模态框</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>这是第一个模态框的内容。</p>
<p>点击下面的按钮可以打开第二个模态框。</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#nestedModal2">
打开第二个模态框
</button>
</div>
</div>
</div>
</div>
<!-- 第二个嵌套模态框 -->
<div class="modal fade" id="nestedModal2" tabindex="-1" aria-labelledby="nestedModal2Label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="nestedModal2Label">第二个模态框</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>这是第二个模态框的内容。</p>
<p>这个模态框是从第一个模态框中打开的。</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">确认</button>
</div>
</div>
</div>
</div>
</div>
<script>
// 表单验证
document.getElementById('registrationForm').addEventListener('submit', function(e) {
e.preventDefault();
const form = this;
const username = document.getElementById('username');
const email = document.getElementById('email');
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirmPassword');
const agreeTerms = document.getElementById('agreeTerms');
let isValid = true;
// 重置验证状态
form.classList.remove('was-validated');
// 验证用户名
if (!username.value.trim()) {
username.setCustomValidity('请输入用户名');
isValid = false;
} else {
username.setCustomValidity('');
}
// 验证邮箱
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email.value)) {
email.setCustomValidity('请输入有效的邮箱地址');
isValid = false;
} else {
email.setCustomValidity('');
}
// 验证密码
if (password.value.length < 6) {
password.setCustomValidity('密码至少需要6个字符');
isValid = false;
} else {
password.setCustomValidity('');
}
// 验证确认密码
if (password.value !== confirmPassword.value) {
confirmPassword.setCustomValidity('密码不匹配');
isValid = false;
} else {
confirmPassword.setCustomValidity('');
}
// 验证服务条款
if (!agreeTerms.checked) {
agreeTerms.setCustomValidity('请同意服务条款');
isValid = false;
} else {
agreeTerms.setCustomValidity('');
}
form.classList.add('was-validated');
if (isValid) {
alert('注册成功!');
bootstrap.Modal.getInstance(document.getElementById('formModal')).hide();
form.reset();
form.classList.remove('was-validated');
}
});
// 动态模态框
function showDynamicModal() {
const modalHtml = `
<div class="modal fade" id="dynamicModal" tabindex="-1" aria-labelledby="dynamicModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="dynamicModalLabel">动态创建的模态框</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>这个模态框是通过 JavaScript 动态创建的。</p>
<p>创建时间:${new Date().toLocaleString()}</p>
<div class="alert alert-success" role="alert">
<i class="bi bi-check-circle"></i> 动态内容加载成功!
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" onclick="updateDynamicContent()">更新内容</button>
</div>
</div>
</div>
</div>
`;
// 移除已存在的动态模态框
const existingModal = document.getElementById('dynamicModal');
if (existingModal) {
existingModal.remove();
}
// 添加新的模态框到页面
document.body.insertAdjacentHTML('beforeend', modalHtml);
// 显示模态框
const modal = new bootstrap.Modal(document.getElementById('dynamicModal'));
modal.show();
// 监听模态框关闭事件,清理DOM
document.getElementById('dynamicModal').addEventListener('hidden.bs.modal', function() {
this.remove();
});
}
function updateDynamicContent() {
const modalBody = document.querySelector('#dynamicModal .modal-body');
modalBody.innerHTML = `
<p>内容已更新!</p>
<p>更新时间:${new Date().toLocaleString()}</p>
<div class="alert alert-info" role="alert">
<i class="bi bi-info-circle"></i> 这是更新后的内容。
</div>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 75%" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">75%</div>
</div>
`;
}
</script>
轮播图组件
1. 基础轮播图
<!-- 轮播图组件示例 -->
<div class="container my-4">
<h2 class="text-primary mb-4">轮播图组件</h2>
<!-- 基础轮播图 -->
<div class="mb-5">
<h5>基础轮播图</h5>
<div id="basicCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-indicators">
<button type="button" data-bs-target="#basicCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
<button type="button" data-bs-target="#basicCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button>
<button type="button" data-bs-target="#basicCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button>
</div>
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://via.placeholder.com/800x400/007bff/ffffff?text=Slide+1" class="d-block w-100" alt="第一张幻灯片">
<div class="carousel-caption d-none d-md-block">
<h5>第一张幻灯片标题</h5>
<p>这是第一张幻灯片的描述文本。</p>
</div>
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/800x400/28a745/ffffff?text=Slide+2" class="d-block w-100" alt="第二张幻灯片">
<div class="carousel-caption d-none d-md-block">
<h5>第二张幻灯片标题</h5>
<p>这是第二张幻灯片的描述文本。</p>
</div>
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/800x400/ffc107/000000?text=Slide+3" class="d-block w-100" alt="第三张幻灯片">
<div class="carousel-caption d-none d-md-block">
<h5>第三张幻灯片标题</h5>
<p>这是第三张幻灯片的描述文本。</p>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#basicCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#basicCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
<!-- 产品展示轮播图 -->
<div class="mb-5">
<h5>产品展示轮播图</h5>
<div id="productCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<div class="row">
<div class="col-md-6">
<img src="https://via.placeholder.com/400x300" class="img-fluid rounded" alt="产品图片">
</div>
<div class="col-md-6 d-flex align-items-center">
<div>
<h4>智能手机 Pro</h4>
<p class="text-muted">最新款智能手机,配备先进的处理器和高清摄像头。</p>
<ul>
<li>6.7英寸 OLED 显示屏</li>
<li>128GB 存储空间</li>
<li>三摄像头系统</li>
<li>5G 网络支持</li>
</ul>
<div class="d-flex align-items-center">
<span class="h4 text-primary me-3">¥4,999</span>
<span class="text-muted text-decoration-line-through">¥5,999</span>
</div>
<button class="btn btn-primary mt-3">立即购买</button>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="row">
<div class="col-md-6">
<img src="https://via.placeholder.com/400x300" class="img-fluid rounded" alt="产品图片">
</div>
<div class="col-md-6 d-flex align-items-center">
<div>
<h4>无线耳机 Max</h4>
<p class="text-muted">高品质无线耳机,提供卓越的音质体验。</p>
<ul>
<li>主动降噪技术</li>
<li>30小时续航</li>
<li>快速充电</li>
<li>防水设计</li>
</ul>
<div class="d-flex align-items-center">
<span class="h4 text-primary me-3">¥1,299</span>
<span class="text-muted text-decoration-line-through">¥1,599</span>
</div>
<button class="btn btn-primary mt-3">立即购买</button>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="row">
<div class="col-md-6">
<img src="https://via.placeholder.com/400x300" class="img-fluid rounded" alt="产品图片">
</div>
<div class="col-md-6 d-flex align-items-center">
<div>
<h4>智能手表 Sport</h4>
<p class="text-muted">专业运动智能手表,追踪您的健康数据。</p>
<ul>
<li>GPS 定位</li>
<li>心率监测</li>
<li>防水50米</li>
<li>7天续航</li>
</ul>
<div class="d-flex align-items-center">
<span class="h4 text-primary me-3">¥2,199</span>
<span class="text-muted text-decoration-line-through">¥2,699</span>
</div>
<button class="btn btn-primary mt-3">立即购买</button>
</div>
</div>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#productCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#productCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
<!-- 缩略图轮播图 -->
<div class="mb-5">
<h5>缩略图轮播图</h5>
<div id="thumbnailCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://via.placeholder.com/800x400/dc3545/ffffff?text=Image+1" class="d-block w-100" alt="图片1">
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/800x400/198754/ffffff?text=Image+2" class="d-block w-100" alt="图片2">
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/800x400/fd7e14/ffffff?text=Image+3" class="d-block w-100" alt="图片3">
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/800x400/6f42c1/ffffff?text=Image+4" class="d-block w-100" alt="图片4">
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#thumbnailCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#thumbnailCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<!-- 缩略图导航 -->
<div class="row mt-3">
<div class="col-3">
<img src="https://via.placeholder.com/200x120/dc3545/ffffff?text=1" class="img-fluid thumbnail-nav active" data-bs-target="#thumbnailCarousel" data-bs-slide-to="0" alt="缩略图1">
</div>
<div class="col-3">
<img src="https://via.placeholder.com/200x120/198754/ffffff?text=2" class="img-fluid thumbnail-nav" data-bs-target="#thumbnailCarousel" data-bs-slide-to="1" alt="缩略图2">
</div>
<div class="col-3">
<img src="https://via.placeholder.com/200x120/fd7e14/ffffff?text=3" class="img-fluid thumbnail-nav" data-bs-target="#thumbnailCarousel" data-bs-slide-to="2" alt="缩略图3">
</div>
<div class="col-3">
<img src="https://via.placeholder.com/200x120/6f42c1/ffffff?text=4" class="img-fluid thumbnail-nav" data-bs-target="#thumbnailCarousel" data-bs-slide-to="3" alt="缩略图4">
</div>
</div>
</div>
</div>
<style>
.thumbnail-nav {
cursor: pointer;
border: 3px solid transparent;
border-radius: 8px;
transition: all 0.3s ease;
}
.thumbnail-nav:hover {
border-color: #007bff;
opacity: 0.8;
}
.thumbnail-nav.active {
border-color: #007bff;
box-shadow: 0 0 10px rgba(0, 123, 255, 0.3);
}
.carousel-item {
transition: transform 0.6s ease-in-out;
}
.carousel-caption {
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
padding: 20px;
}
</style>
<script>
// 缩略图导航功能
document.addEventListener('DOMContentLoaded', function() {
const thumbnailNavs = document.querySelectorAll('.thumbnail-nav');
const carousel = document.getElementById('thumbnailCarousel');
thumbnailNavs.forEach((thumbnail, index) => {
thumbnail.addEventListener('click', function() {
// 移除所有活动状态
thumbnailNavs.forEach(nav => nav.classList.remove('active'));
// 添加当前活动状态
this.classList.add('active');
// 切换轮播图
const carouselInstance = bootstrap.Carousel.getInstance(carousel);
carouselInstance.to(index);
});
});
// 监听轮播图切换事件,同步缩略图状态
carousel.addEventListener('slide.bs.carousel', function(e) {
thumbnailNavs.forEach(nav => nav.classList.remove('active'));
thumbnailNavs[e.to].classList.add('active');
});
});
</script>
折叠面板组件
1. 基础折叠面板
<!-- 折叠面板组件示例 -->
<div class="container my-4">
<h2 class="text-primary mb-4">折叠面板组件</h2>
<!-- 基础折叠面板 -->
<div class="mb-5">
<h5>基础折叠面板</h5>
<div class="accordion" id="basicAccordion">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
什么是 Bootstrap?
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#basicAccordion">
<div class="accordion-body">
Bootstrap 是一个开源的前端框架,用于快速开发响应式和移动优先的网站。它包含了 HTML、CSS 和 JavaScript 组件,可以帮助开发者快速构建现代化的用户界面。
<div class="mt-3">
<strong>主要特性:</strong>
<ul class="mt-2">
<li>响应式网格系统</li>
<li>丰富的组件库</li>
<li>强大的工具类</li>
<li>JavaScript 插件</li>
</ul>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
如何安装 Bootstrap?
</button>
</h2>
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#basicAccordion">
<div class="accordion-body">
有多种方式可以安装和使用 Bootstrap:
<div class="mt-3">
<h6>1. CDN 方式</h6>
<pre class="bg-light p-3 rounded"><code><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script></code></pre>
<h6 class="mt-3">2. npm 安装</h6>
<pre class="bg-light p-3 rounded"><code>npm install bootstrap</code></pre>
<h6 class="mt-3">3. 下载源码</h6>
<p>从官网下载编译好的 CSS 和 JS 文件。</p>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingThree">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
Bootstrap 的优势是什么?
</button>
</h2>
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#basicAccordion">
<div class="accordion-body">
Bootstrap 具有以下主要优势:
<div class="row mt-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-body">
<h6 class="card-title text-primary">开发效率</h6>
<p class="card-text">预构建的组件和工具类大大提高了开发速度。</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-body">
<h6 class="card-title text-success">响应式设计</h6>
<p class="card-text">内置的响应式网格系统适配各种设备。</p>
</div>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-body">
<h6 class="card-title text-warning">浏览器兼容</h6>
<p class="card-text">良好的跨浏览器兼容性支持。</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-body">
<h6 class="card-title text-info">社区支持</h6>
<p class="card-text">庞大的社区和丰富的文档资源。</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- FAQ 折叠面板 -->
<div class="mb-5">
<h5>常见问题 FAQ</h5>
<div class="accordion" id="faqAccordion">
<div class="accordion-item">
<h2 class="accordion-header" id="faqHeading1">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse1" aria-expanded="false" aria-controls="faqCollapse1">
<i class="bi bi-question-circle me-2"></i>
如何自定义 Bootstrap 主题?
</button>
</h2>
<div id="faqCollapse1" class="accordion-collapse collapse" aria-labelledby="faqHeading1" data-bs-parent="#faqAccordion">
<div class="accordion-body">
<p>自定义 Bootstrap 主题有几种方法:</p>
<div class="alert alert-info" role="alert">
<strong>推荐方法:</strong> 使用 Sass 变量来自定义主题颜色和样式。
</div>
<ol>
<li><strong>修改 Sass 变量:</strong> 在导入 Bootstrap 之前定义自己的变量</li>
<li><strong>使用 CSS 变量:</strong> 通过 CSS 自定义属性覆盖默认样式</li>
<li><strong>编写自定义 CSS:</strong> 创建额外的样式表覆盖默认样式</li>
</ol>
<div class="mt-3">
<button class="btn btn-outline-primary btn-sm">查看示例</button>
<button class="btn btn-outline-secondary btn-sm">下载模板</button>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="faqHeading2">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse2" aria-expanded="false" aria-controls="faqCollapse2">
<i class="bi bi-gear me-2"></i>
Bootstrap 5 与 Bootstrap 4 有什么区别?
</button>
</h2>
<div id="faqCollapse2" class="accordion-collapse collapse" aria-labelledby="faqHeading2" data-bs-parent="#faqAccordion">
<div class="accordion-body">
<p>Bootstrap 5 相比 Bootstrap 4 有以下主要改进:</p>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>特性</th>
<th>Bootstrap 4</th>
<th>Bootstrap 5</th>
</tr>
</thead>
<tbody>
<tr>
<td>jQuery 依赖</td>
<td>需要 jQuery</td>
<td>不需要 jQuery</td>
</tr>
<tr>
<td>CSS 变量</td>
<td>有限支持</td>
<td>广泛使用</td>
</tr>
<tr>
<td>工具类</td>
<td>基础工具类</td>
<td>更多工具类</td>
</tr>
<tr>
<td>表单控件</td>
<td>传统样式</td>
<td>现代化样式</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="faqHeading3">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse3" aria-expanded="false" aria-controls="faqCollapse3">
<i class="bi bi-phone me-2"></i>
如何确保网站在移动设备上正常显示?
</button>
</h2>
<div id="faqCollapse3" class="accordion-collapse collapse" aria-labelledby="faqHeading3" data-bs-parent="#faqAccordion">
<div class="accordion-body">
<p>确保移动设备兼容性的关键步骤:</p>
<div class="row">
<div class="col-md-6">
<h6 class="text-primary">1. 设置视口</h6>
<pre class="bg-light p-2 rounded small"><code><meta name="viewport" content="width=device-width, initial-scale=1"></code></pre>
<h6 class="text-primary mt-3">2. 使用响应式网格</h6>
<p class="small">使用 Bootstrap 的网格系统创建响应式布局。</p>
</div>
<div class="col-md-6">
<h6 class="text-primary">3. 测试不同设备</h6>
<p class="small">在不同尺寸的设备上测试网站效果。</p>
<h6 class="text-primary mt-3">4. 优化图片</h6>
<p class="small">使用响应式图片和适当的文件格式。</p>
</div>
</div>
<div class="alert alert-warning mt-3" role="alert">
<i class="bi bi-exclamation-triangle"></i>
<strong>注意:</strong> 始终在真实设备上测试,不要仅依赖浏览器的开发者工具。
</div>
</div>
</div>
</div>
</div>
</div>
</div>
工具提示和弹出框
1. 工具提示组件
<!-- 工具提示和弹出框示例 -->
<div class="container my-4">
<h2 class="text-primary mb-4">工具提示和弹出框</h2>
<!-- 工具提示示例 -->
<div class="mb-5">
<h5>工具提示 (Tooltips)</h5>
<p>将鼠标悬停在下面的按钮上查看工具提示效果:</p>
<div class="d-flex flex-wrap gap-2 mb-3">
<button type="button" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="顶部工具提示">
顶部提示
</button>
<button type="button" class="btn btn-success" data-bs-toggle="tooltip" data-bs-placement="right" title="右侧工具提示">
右侧提示
</button>
<button type="button" class="btn btn-warning" data-bs-toggle="tooltip" data-bs-placement="bottom" title="底部工具提示">
底部提示
</button>
<button type="button" class="btn btn-info" data-bs-toggle="tooltip" data-bs-placement="left" title="左侧工具提示">
左侧提示
</button>
</div>
<div class="mb-3">
<p>工具提示也可以应用于其他元素:</p>
<p>
这是一段包含
<a href="#" data-bs-toggle="tooltip" title="这是一个链接的工具提示">链接</a>
和
<span class="badge bg-secondary" data-bs-toggle="tooltip" title="这是一个徽章的工具提示">徽章</span>
的文本。
</p>
</div>
<!-- HTML 内容的工具提示 -->
<div class="mb-3">
<button type="button" class="btn btn-outline-primary"
data-bs-toggle="tooltip"
data-bs-html="true"
title="<strong>HTML 工具提示</strong><br>支持 <em>HTML</em> 格式">
HTML 工具提示
</button>
</div>
</div>
<!-- 弹出框示例 -->
<div class="mb-5">
<h5>弹出框 (Popovers)</h5>
<p>点击下面的按钮查看弹出框效果:</p>
<div class="d-flex flex-wrap gap-2 mb-3">
<button type="button" class="btn btn-primary"
data-bs-toggle="popover"
data-bs-placement="top"
title="顶部弹出框"
data-bs-content="这是顶部弹出框的内容。可以包含更多的文本信息。">
顶部弹出框
</button>
<button type="button" class="btn btn-success"
data-bs-toggle="popover"
data-bs-placement="right"
title="右侧弹出框"
data-bs-content="这是右侧弹出框的内容。">
右侧弹出框
</button>
<button type="button" class="btn btn-warning"
data-bs-toggle="popover"
data-bs-placement="bottom"
title="底部弹出框"
data-bs-content="这是底部弹出框的内容。">
底部弹出框
</button>
<button type="button" class="btn btn-info"
data-bs-toggle="popover"
data-bs-placement="left"
title="左侧弹出框"
data-bs-content="这是左侧弹出框的内容。">
左侧弹出框
</button>
</div>
<!-- 可关闭的弹出框 -->
<div class="mb-3">
<button type="button" class="btn btn-outline-danger"
data-bs-toggle="popover"
data-bs-trigger="focus"
title="可关闭的弹出框"
data-bs-content="点击其他地方可以关闭这个弹出框。">
可关闭弹出框
</button>
</div>
<!-- HTML 内容的弹出框 -->
<div class="mb-3">
<button type="button" class="btn btn-outline-success"
data-bs-toggle="popover"
data-bs-html="true"
title="<strong>用户信息</strong>"
data-bs-content="<div class='text-center'><img src='https://via.placeholder.com/50x50' class='rounded-circle mb-2'><br><strong>张三</strong><br><small class='text-muted'>前端开发工程师</small></div>">
用户信息
</button>
</div>
</div>
<!-- 实际应用示例 -->
<div class="mb-5">
<h5>实际应用示例</h5>
<!-- 表单帮助提示 -->
<div class="card">
<div class="card-header">
<h6 class="mb-0">用户注册表单</h6>
</div>
<div class="card-body">
<form>
<div class="mb-3">
<label for="username" class="form-label">
用户名
<i class="bi bi-question-circle text-muted"
data-bs-toggle="tooltip"
title="用户名长度为3-20个字符,只能包含字母、数字和下划线"></i>
</label>
<input type="text" class="form-control" id="username" placeholder="请输入用户名">
</div>
<div class="mb-3">
<label for="email" class="form-label">
邮箱地址
<i class="bi bi-info-circle text-primary"
data-bs-toggle="popover"
data-bs-trigger="hover"
title="邮箱验证"
data-bs-content="我们会向您的邮箱发送验证链接,请确保邮箱地址正确。"></i>
</label>
<input type="email" class="form-control" id="email" placeholder="请输入邮箱地址">
</div>
<div class="mb-3">
<label for="password" class="form-label">
密码
<i class="bi bi-shield-check text-success"
data-bs-toggle="popover"
data-bs-html="true"
title="密码强度要求"
data-bs-content="<ul><li>至少8个字符</li><li>包含大小写字母</li><li>包含数字</li><li>包含特殊字符</li></ul>"></i>
</label>
<input type="password" class="form-control" id="password" placeholder="请输入密码">
</div>
<button type="submit" class="btn btn-primary">注册</button>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 初始化工具提示
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// 初始化弹出框
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
</script>
</body>
</html>
进度条组件
1. 基础进度条
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap 进度条组件</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container my-5">
<h2 class="text-primary mb-4">进度条组件</h2>
<!-- 基础进度条 -->
<div class="mb-4">
<h5>基础进度条</h5>
<div class="progress mb-3">
<div class="progress-bar" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-3">
<div class="progress-bar" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">50%</div>
</div>
<div class="progress mb-3">
<div class="progress-bar" role="progressbar" style="width: 75%" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">75%</div>
</div>
</div>
<!-- 不同颜色的进度条 -->
<div class="mb-4">
<h5>不同颜色的进度条</h5>
<div class="progress mb-2">
<div class="progress-bar bg-success" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar bg-info" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar bg-warning" role="progressbar" style="width: 75%" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar bg-danger" role="progressbar" style="width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<!-- 条纹进度条 -->
<div class="mb-4">
<h5>条纹进度条</h5>
<div class="progress mb-2">
<div class="progress-bar progress-bar-striped" role="progressbar" style="width: 10%" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar progress-bar-striped bg-success" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar progress-bar-striped bg-info" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar progress-bar-striped bg-warning" role="progressbar" style="width: 75%" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress mb-2">
<div class="progress-bar progress-bar-striped bg-danger" role="progressbar" style="width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<!-- 动画进度条 -->
<div class="mb-4">
<h5>动画进度条</h5>
<div class="progress mb-2">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 75%"></div>
</div>
</div>
<!-- 多重进度条 -->
<div class="mb-4">
<h5>多重进度条</h5>
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: 15%" aria-valuenow="15" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar bg-success" role="progressbar" style="width: 30%" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 20%" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<!-- 动态进度条 -->
<div class="mb-4">
<h5>动态进度条</h5>
<div class="progress mb-3">
<div class="progress-bar" id="dynamicProgress" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>
</div>
<button class="btn btn-primary" onclick="startProgress()">开始进度</button>
<button class="btn btn-secondary ms-2" onclick="resetProgress()">重置进度</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
let progressInterval;
function startProgress() {
const progressBar = document.getElementById('dynamicProgress');
let width = 0;
progressInterval = setInterval(() => {
if (width >= 100) {
clearInterval(progressInterval);
} else {
width++;
progressBar.style.width = width + '%';
progressBar.setAttribute('aria-valuenow', width);
progressBar.textContent = width + '%';
}
}, 50);
}
function resetProgress() {
clearInterval(progressInterval);
const progressBar = document.getElementById('dynamicProgress');
progressBar.style.width = '0%';
progressBar.setAttribute('aria-valuenow', 0);
progressBar.textContent = '0%';
}
</script>
</body>
</html>
列表组组件
1. 基础列表组
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap 列表组组件</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container my-5">
<h2 class="text-primary mb-4">列表组组件</h2>
<div class="row">
<!-- 基础列表组 -->
<div class="col-md-6 mb-4">
<h5>基础列表组</h5>
<ul class="list-group">
<li class="list-group-item">第一个项目</li>
<li class="list-group-item">第二个项目</li>
<li class="list-group-item">第三个项目</li>
<li class="list-group-item">第四个项目</li>
<li class="list-group-item">第五个项目</li>
</ul>
</div>
<!-- 活动和禁用项目 -->
<div class="col-md-6 mb-4">
<h5>活动和禁用项目</h5>
<ul class="list-group">
<li class="list-group-item active">活动项目</li>
<li class="list-group-item">普通项目</li>
<li class="list-group-item disabled">禁用项目</li>
<li class="list-group-item">普通项目</li>
</ul>
</div>
<!-- 链接列表组 -->
<div class="col-md-6 mb-4">
<h5>链接列表组</h5>
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action active">首页</a>
<a href="#" class="list-group-item list-group-item-action">产品</a>
<a href="#" class="list-group-item list-group-item-action">服务</a>
<a href="#" class="list-group-item list-group-item-action disabled">联系我们</a>
</div>
</div>
<!-- 按钮列表组 -->
<div class="col-md-6 mb-4">
<h5>按钮列表组</h5>
<div class="list-group">
<button type="button" class="list-group-item list-group-item-action active">当前按钮</button>
<button type="button" class="list-group-item list-group-item-action">第二个按钮</button>
<button type="button" class="list-group-item list-group-item-action">第三个按钮</button>
<button type="button" class="list-group-item list-group-item-action" disabled>禁用按钮</button>
</div>
</div>
<!-- 带徽章的列表组 -->
<div class="col-md-6 mb-4">
<h5>带徽章的列表组</h5>
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center">
收件箱
<span class="badge bg-primary rounded-pill">14</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
已发送
<span class="badge bg-secondary rounded-pill">2</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
草稿箱
<span class="badge bg-warning rounded-pill">1</span>
</li>
</ul>
</div>
<!-- 自定义内容列表组 -->
<div class="col-md-6 mb-4">
<h5>自定义内容列表组</h5>
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">列表组项目标题</h5>
<small>3天前</small>
</div>
<p class="mb-1">这是一些占位符内容,用于演示列表组项目中的自定义内容。</p>
<small>更多详细信息...</small>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">另一个标题</h5>
<small class="text-muted">3天前</small>
</div>
<p class="mb-1">这是另一个列表组项目的内容。</p>
<small class="text-muted">更多信息...</small>
</a>
</div>
</div>
</div>
<!-- 彩色列表组 -->
<div class="mb-4">
<h5>彩色列表组</h5>
<ul class="list-group">
<li class="list-group-item">默认列表组项目</li>
<li class="list-group-item list-group-item-primary">主要列表组项目</li>
<li class="list-group-item list-group-item-secondary">次要列表组项目</li>
<li class="list-group-item list-group-item-success">成功列表组项目</li>
<li class="list-group-item list-group-item-danger">危险列表组项目</li>
<li class="list-group-item list-group-item-warning">警告列表组项目</li>
<li class="list-group-item list-group-item-info">信息列表组项目</li>
<li class="list-group-item list-group-item-light">浅色列表组项目</li>
<li class="list-group-item list-group-item-dark">深色列表组项目</li>
</ul>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
实际应用案例
1. 任务管理面板
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>任务管理面板</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
</head>
<body>
<div class="container my-5">
<h2 class="text-primary mb-4">任务管理面板</h2>
<!-- 任务统计卡片 -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="card text-white bg-primary">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">24</h4>
<p class="card-text">总任务</p>
</div>
<div class="align-self-center">
<i class="bi bi-list-task fs-1"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card text-white bg-success">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">18</h4>
<p class="card-text">已完成</p>
</div>
<div class="align-self-center">
<i class="bi bi-check-circle fs-1"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card text-white bg-warning">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">4</h4>
<p class="card-text">进行中</p>
</div>
<div class="align-self-center">
<i class="bi bi-clock fs-1"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card text-white bg-danger">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">2</h4>
<p class="card-text">逾期</p>
</div>
<div class="align-self-center">
<i class="bi bi-exclamation-triangle fs-1"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 项目进度 -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">项目进度</h5>
</div>
<div class="card-body">
<div class="mb-3">
<div class="d-flex justify-content-between mb-1">
<span>网站重构项目</span>
<span>75%</span>
</div>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 75%" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="mb-3">
<div class="d-flex justify-content-between mb-1">
<span>移动应用开发</span>
<span>45%</span>
</div>
<div class="progress">
<div class="progress-bar bg-info" role="progressbar" style="width: 45%" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="mb-3">
<div class="d-flex justify-content-between mb-1">
<span>数据库优化</span>
<span>90%</span>
</div>
<div class="progress">
<div class="progress-bar bg-warning" role="progressbar" style="width: 90%" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<!-- 任务列表 -->
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">最近任务</h5>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addTaskModal">
<i class="bi bi-plus"></i> 添加任务
</button>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush">
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">完成用户界面设计</div>
<small class="text-muted">截止日期: 2024-01-15</small>
</div>
<span class="badge bg-success rounded-pill">已完成</span>
</div>
</div>
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">实现用户认证功能</div>
<small class="text-muted">截止日期: 2024-01-20</small>
</div>
<span class="badge bg-warning rounded-pill">进行中</span>
</div>
</div>
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">数据库性能优化</div>
<small class="text-muted">截止日期: 2024-01-25</small>
</div>
<span class="badge bg-primary rounded-pill">待开始</span>
</div>
</div>
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">编写API文档</div>
<small class="text-muted">截止日期: 2024-01-10</small>
</div>
<span class="badge bg-danger rounded-pill">逾期</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加任务模态框 -->
<div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addTaskModalLabel">添加新任务</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-3">
<label for="taskTitle" class="form-label">任务标题</label>
<input type="text" class="form-control" id="taskTitle" placeholder="请输入任务标题">
</div>
<div class="mb-3">
<label for="taskDescription" class="form-label">任务描述</label>
<textarea class="form-control" id="taskDescription" rows="3" placeholder="请输入任务描述"></textarea>
</div>
<div class="mb-3">
<label for="taskPriority" class="form-label">优先级</label>
<select class="form-select" id="taskPriority">
<option value="low">低</option>
<option value="medium" selected>中</option>
<option value="high">高</option>
</select>
</div>
<div class="mb-3">
<label for="taskDeadline" class="form-label">截止日期</label>
<input type="date" class="form-control" id="taskDeadline">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary">添加任务</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
自定义高级组件样式
1. 自定义模态框样式
/* 自定义模态框样式 */
.custom-modal .modal-content {
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
border: none;
}
.custom-modal .modal-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 15px 15px 0 0;
border-bottom: none;
}
.custom-modal .modal-header .btn-close {
filter: invert(1);
}
.custom-modal .modal-body {
padding: 2rem;
}
.custom-modal .modal-footer {
border-top: 1px solid #e9ecef;
padding: 1rem 2rem;
}
/* 自定义进度条样式 */
.custom-progress {
height: 20px;
border-radius: 10px;
background-color: #f8f9fa;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
.custom-progress .progress-bar {
border-radius: 10px;
background: linear-gradient(45deg, #ff6b6b, #ee5a24);
position: relative;
overflow: hidden;
}
.custom-progress .progress-bar::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(
45deg,
transparent 25%,
rgba(255, 255, 255, 0.2) 25%,
rgba(255, 255, 255, 0.2) 50%,
transparent 50%,
transparent 75%,
rgba(255, 255, 255, 0.2) 75%
);
background-size: 20px 20px;
animation: progress-animation 1s linear infinite;
}
@keyframes progress-animation {
0% {
background-position: 0 0;
}
100% {
background-position: 20px 0;
}
}
/* 自定义列表组样式 */
.custom-list-group {
border-radius: 15px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.custom-list-group .list-group-item {
border: none;
border-bottom: 1px solid #e9ecef;
transition: all 0.3s ease;
}
.custom-list-group .list-group-item:hover {
background-color: #f8f9fa;
transform: translateX(5px);
}
.custom-list-group .list-group-item:last-child {
border-bottom: none;
}
.custom-list-group .list-group-item.active {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-color: transparent;
}
响应式高级组件优化
1. 响应式模态框
/* 响应式模态框 */
@media (max-width: 576px) {
.modal-dialog {
margin: 0.5rem;
}
.modal-fullscreen-sm-down {
width: 100vw;
max-width: none;
height: 100%;
margin: 0;
}
.modal-fullscreen-sm-down .modal-content {
height: 100%;
border: 0;
border-radius: 0;
}
.modal-fullscreen-sm-down .modal-header,
.modal-fullscreen-sm-down .modal-footer {
border-radius: 0;
}
}
/* 响应式进度条 */
@media (max-width: 768px) {
.progress {
height: 15px;
}
.progress-bar {
font-size: 0.75rem;
}
}
/* 响应式列表组 */
@media (max-width: 576px) {
.list-group-item {
padding: 0.75rem 1rem;
}
.list-group-item .d-flex {
flex-direction: column;
align-items: flex-start !important;
}
.list-group-item .badge {
margin-top: 0.5rem;
align-self: flex-start;
}
}
高级组件可访问性
1. 键盘导航支持
// 高级组件键盘导航
class AccessibleComponents {
constructor() {
this.initModalKeyboard();
this.initListGroupKeyboard();
this.initProgressAnnouncement();
}
// 模态框键盘支持
initModalKeyboard() {
document.addEventListener('keydown', (e) => {
const activeModal = document.querySelector('.modal.show');
if (!activeModal) return;
// ESC键关闭模态框
if (e.key === 'Escape') {
const modal = bootstrap.Modal.getInstance(activeModal);
if (modal) modal.hide();
}
// Tab键焦点管理
if (e.key === 'Tab') {
this.trapFocus(activeModal, e);
}
});
}
// 焦点陷阱
trapFocus(modal, e) {
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (e.shiftKey) {
if (document.activeElement === firstElement) {
lastElement.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastElement) {
firstElement.focus();
e.preventDefault();
}
}
}
// 列表组键盘导航
initListGroupKeyboard() {
const listGroups = document.querySelectorAll('.list-group');
listGroups.forEach(listGroup => {
const items = listGroup.querySelectorAll('.list-group-item');
items.forEach((item, index) => {
item.setAttribute('tabindex', index === 0 ? '0' : '-1');
item.addEventListener('keydown', (e) => {
let targetIndex = index;
switch (e.key) {
case 'ArrowDown':
targetIndex = (index + 1) % items.length;
break;
case 'ArrowUp':
targetIndex = (index - 1 + items.length) % items.length;
break;
case 'Home':
targetIndex = 0;
break;
case 'End':
targetIndex = items.length - 1;
break;
default:
return;
}
e.preventDefault();
// 更新tabindex
items.forEach(i => i.setAttribute('tabindex', '-1'));
items[targetIndex].setAttribute('tabindex', '0');
items[targetIndex].focus();
});
});
});
}
// 进度条状态播报
initProgressAnnouncement() {
const progressBars = document.querySelectorAll('.progress-bar');
progressBars.forEach(bar => {
// 创建屏幕阅读器公告区域
const announcement = document.createElement('div');
announcement.setAttribute('aria-live', 'polite');
announcement.setAttribute('aria-atomic', 'true');
announcement.className = 'sr-only';
bar.parentNode.appendChild(announcement);
// 监听进度变化
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'attributes' && mutation.attributeName === 'aria-valuenow') {
const value = bar.getAttribute('aria-valuenow');
announcement.textContent = `进度更新: ${value}%`;
}
});
});
observer.observe(bar, {
attributes: true,
attributeFilter: ['aria-valuenow']
});
});
}
}
// 初始化可访问性功能
document.addEventListener('DOMContentLoaded', () => {
new AccessibleComponents();
});
2. ARIA标签优化
<!-- 优化的模态框ARIA标签 -->
<div class="modal fade" id="accessibleModal" tabindex="-1"
aria-labelledby="accessibleModalLabel"
aria-describedby="accessibleModalDesc"
aria-hidden="true"
role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="accessibleModalLabel">可访问的模态框</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"
aria-label="关闭模态框"></button>
</div>
<div class="modal-body">
<p id="accessibleModalDesc">这是一个具有完整可访问性支持的模态框示例。</p>
</div>
</div>
</div>
</div>
<!-- 优化的进度条ARIA标签 -->
<div class="progress" role="progressbar"
aria-label="文件上传进度"
aria-describedby="progressDesc">
<div class="progress-bar"
style="width: 60%"
aria-valuenow="60"
aria-valuemin="0"
aria-valuemax="100">
60%
</div>
</div>
<div id="progressDesc" class="sr-only">文件上传进度: 60% 完成</div>
<!-- 优化的列表组ARIA标签 -->
<div class="list-group" role="listbox" aria-label="任务列表">
<div class="list-group-item" role="option" aria-selected="true">
<span class="fw-bold">完成项目文档</span>
<span class="badge bg-success ms-auto" aria-label="状态: 已完成">已完成</span>
</div>
<div class="list-group-item" role="option" aria-selected="false">
<span class="fw-bold">代码审查</span>
<span class="badge bg-warning ms-auto" aria-label="状态: 进行中">进行中</span>
</div>
</div>
性能优化建议
1. 组件懒加载
// 高级组件懒加载
class ComponentLazyLoader {
constructor() {
this.observeComponents();
}
observeComponents() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadComponent(entry.target);
observer.unobserve(entry.target);
}
});
}, {
rootMargin: '50px'
});
// 观察需要懒加载的组件
document.querySelectorAll('[data-lazy-component]').forEach(el => {
observer.observe(el);
});
}
loadComponent(element) {
const componentType = element.dataset.lazyComponent;
switch (componentType) {
case 'carousel':
this.loadCarousel(element);
break;
case 'modal':
this.loadModal(element);
break;
case 'tooltip':
this.loadTooltip(element);
break;
case 'popover':
this.loadPopover(element);
break;
}
}
loadCarousel(element) {
// 动态加载轮播图内容
const images = element.dataset.images.split(',');
const carouselInner = element.querySelector('.carousel-inner');
images.forEach((src, index) => {
const item = document.createElement('div');
item.className = `carousel-item ${index === 0 ? 'active' : ''}`;
item.innerHTML = `<img src="${src}" class="d-block w-100" alt="图片 ${index + 1}">`;
carouselInner.appendChild(item);
});
// 初始化轮播图
new bootstrap.Carousel(element);
}
loadModal(element) {
// 动态加载模态框内容
const contentUrl = element.dataset.contentUrl;
if (contentUrl) {
fetch(contentUrl)
.then(response => response.text())
.then(html => {
element.querySelector('.modal-body').innerHTML = html;
new bootstrap.Modal(element);
})
.catch(error => {
console.error('加载模态框内容失败:', error);
});
}
}
loadTooltip(element) {
new bootstrap.Tooltip(element);
}
loadPopover(element) {
new bootstrap.Popover(element);
}
}
// 初始化懒加载
document.addEventListener('DOMContentLoaded', () => {
new ComponentLazyLoader();
});
2. 组件缓存优化
// 组件缓存管理
class ComponentCache {
constructor() {
this.cache = new Map();
this.maxCacheSize = 50;
}
// 缓存组件实例
set(key, component) {
if (this.cache.size >= this.maxCacheSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, {
component,
timestamp: Date.now()
});
}
// 获取缓存的组件
get(key) {
const cached = this.cache.get(key);
if (cached) {
// 更新访问时间
cached.timestamp = Date.now();
return cached.component;
}
return null;
}
// 清理过期缓存
cleanup(maxAge = 300000) { // 5分钟
const now = Date.now();
for (const [key, value] of this.cache.entries()) {
if (now - value.timestamp > maxAge) {
this.cache.delete(key);
}
}
}
}
// 全局组件缓存实例
const componentCache = new ComponentCache();
// 定期清理缓存
setInterval(() => {
componentCache.cleanup();
}, 60000); // 每分钟清理一次
本章总结
本章详细介绍了 Bootstrap 的高级组件,包括:
核心组件
- 模态框组件 - 不同尺寸、表单模态框、动态模态框
- 轮播图组件 - 基础轮播、产品展示、缩略图导航
- 折叠面板组件 - 基础折叠、FAQ面板
- 工具提示和弹出框 - 不同位置、HTML内容、交互式弹出框
- 进度条组件 - 基础进度条、条纹动画、多重进度条
- 列表组组件 - 基础列表、链接列表、自定义内容
实际应用
- 任务管理面板综合案例
- 组件间的协同使用
- 数据展示和交互设计
高级技巧
- 自定义组件样式和动画
- 响应式组件优化
- 可访问性支持和ARIA标签
- 性能优化和懒加载
最佳实践
- 合理使用组件层次结构
- 注意组件的可访问性
- 优化组件性能和加载速度
- 保持组件样式的一致性
掌握这些高级组件的使用方法,能够帮助你构建更加丰富、交互性强且用户体验良好的Web应用程序。
练习题
基础练习
- 创建一个包含表单验证的模态框
- 实现一个带有自动播放功能的轮播图
- 制作一个FAQ折叠面板
- 添加工具提示到表单字段
- 创建一个动态更新的进度条
进阶练习
- 实现一个多步骤表单模态框
- 创建一个响应式的图片画廊轮播
- 制作一个可嵌套的折叠面板系统
- 实现一个带有富文本内容的弹出框
- 创建一个实时更新的任务进度面板