基于 jQuery 与 Bootstrap 简单封装一个表格分页的组件
'# 基于 jQuery 与 Bootstrap 简单封装一个表格分页的组件
一、背景与问题
在传统的 Web 开发中,表格分页功能往往需要开发者手动处理数据切片、页码计算、DOM 操作等繁琐逻辑。例如,当需要展示 1000 条数据时,开发者需要:
- 计算总页数
- 动态生成页码按钮
- 根据当前页码渲染表格内容
- 处理页码点击事件
- 处理数据加载的异步逻辑
这种重复性工作在多个页面重复使用时会导致代码冗余。通过封装一个可复用的分页组件,可以解决以下问题:
- 减少 80% 的重复代码
- 统一分页组件样式(基于 Bootstrap)
- 提供统一的 API 接口
- 支持数据异步加载
但需要警惕过度封装带来的问题:对于大数据量场景(如 10w+ 条数据),单纯分页组件无法解决前端性能瓶颈,此时应考虑虚拟滚动技术或后端分页优化。
二、基本原理
分页组件的核心原理包含三个部分:
- 数据分页:将原始数据按页大小进行切片
- UI 更新:根据当前页码动态渲染表格内容
- 交互控制:处理页码点击事件并更新视图
其工作流程如下:
graph TD
A[用户点击页码] --> B{更新页码参数}
B --> C[计算数据切片]
C --> D[更新表格内容]
D --> E[更新分页控件]关键点在于:
- 需要维护当前页码(
currentPage)和页大小(pageSize) - 需要处理数据切片的边界条件(如最后一页的处理)
- 需要处理分页控件的动态生成
三、环境准备
<!-- 引入 jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 引入 Bootstrap -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>建议使用版本:
- jQuery 3.6.0+
- Bootstrap 5.3.2+
四、核心实现
1. 基础组件封装
// 分页组件核心逻辑
(function($) {
$.fn.pagination = function(options) {
// 默认配置
const defaults = {
dataSource: [], // 数据源
pageSize: 10, // 每页大小
currentPage: 1, // 当前页码
onPageChange: null // 分页回调函数
};
// 合并配置
const settings = $.extend({}, defaults, options);
// 构造分页控件
function buildPagination() {
const totalPages = Math.ceil(settings.dataSource.length / settings.pageSize);
const pagination = $('<ul class="pagination"></ul>');
// 生成页码按钮
for (let i = 1; i <= totalPages; i++) {
const pageItem = $('<li class="page-item"><a class="page-link" href="#">' + i + '</a></li>');
pageItem.on('click', function() {
settings.currentPage = i;
renderPage();
});
pagination.append(pageItem);
}
return pagination;
}
// 渲染当前页数据
function renderPage() {
const start = (settings.currentPage - 1) * settings.pageSize;
const end = start + settings.pageSize;
const pageData = settings.dataSource.slice(start, end);
// 清空当前表格内容
$('#dataTable tbody').empty();
// 渲染表格行
pageData.forEach(row => {
const rowElement = $('<tr></tr>');
Object.values(row).forEach(cell => {
rowElement.append($('<td>').text(cell));
});
$('#dataTable tbody').append(rowElement);
});
// 调用回调函数
if (settings.onPageChange) {
settings.onPageChange(settings.currentPage);
}
}
// 初始化
const pagination = buildPagination();
$(this).html(pagination);
renderPage();
return this;
};
})(jQuery);2. 分页控件样式
/* 分页控件样式 */
.pagination {
margin-top: 20px;
}
.pagination .page-link {
cursor: pointer;
padding: 0.5rem 0.75rem;
border-radius: 0.25rem;
}
.pagination .page-item.active .page-link {
background-color: #0d6efd;
border-color: #0d6efd;
}3. 数据处理逻辑
// 模拟数据处理
function fetchData() {
const data = [];
for (let i = 0; i < 100; i++) {
data.push({
id: i + 1,
name: 'Item ' + (i + 1),
description: 'This is item number ' + (i + 1)
});
}
return data;
}五、完整案例
1. HTML 结构
<div id="app">
<table id="dataTable" class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<!-- 表格内容由分页组件动态填充 -->
</tbody>
</table>
<div id="pagination"></div>
</div>2. JavaScript 逻辑
$(document).ready(function() {
const dataSource = fetchData();
// 初始化分页组件
$('#pagination').pagination({
dataSource: dataSource,
pageSize: 10,
onPageChange: function(page) {
console.log('当前页码:', page);
}
});
});3. 运行效果
当页面加载时,会自动渲染 10 条数据,并生成分页控件。点击页码时,会动态更新表格内容,并触发 onPageChange 回调函数。
六、源码解析
1. 构造分页控件的逻辑
function buildPagination() {
const totalPages = Math.ceil(settings.dataSource.length / settings.pageSize);
const pagination = $('<ul class="pagination"></ul>');
for (let i = 1; i <= totalPages; i++) {
const pageItem = $('<li class="page-item"><a class="page-link" href="#">' + i + '</a></li>');
pageItem.on('click', function() {
settings.currentPage = i;
renderPage();
});
pagination.append(pageItem);
}
return pagination;
}- 使用
Math.ceil计算总页数 - 为每个页码创建点击事件处理函数
- 使用
page-link类实现 Bootstrap 的样式
2. 渲染表格内容的逻辑
function renderPage() {
const start = (settings.currentPage - 1) * settings.pageSize;
const end = start + settings.pageSize;
const pageData = settings.dataSource.slice(start, end);
$('#dataTable tbody').empty();
pageData.forEach(row => {
const rowElement = $('<tr></tr>');
Object.values(row).forEach(cell => {
rowElement.append($('<td>').text(cell));
});
$('#dataTable tbody').append(rowElement);
});
}- 使用
slice方法进行数据切片 - 使用
Object.values获取对象的值 - 通过
append动态构建表格行
七、进阶使用
1. 支持动态数据加载
$('#pagination').pagination({
dataSource: function(page, size) {
return fetchData(page, size); // 从后端获取数据
},
pageSize: 10,
onPageChange: function(page) {
console.log('加载第', page, '页数据');
}
});2. 支持自定义分页样式
.pagination .page-item {
margin-right: 5px;
}
.pagination .page-item:last-child {
margin-right: 0;
}3. 支持多种排序方式
$('#pagination').pagination({
dataSource: (page, size, sortField) => {
return fetchData(page, size, sortField);
},
pageSize: 10,
sortField: 'id'
});八、性能与工程实践
1. 性能优化
对于大数据量场景(如 10w+ 条数据),建议:
- 使用虚拟滚动技术(如 vue-virtual-scroll-list)
- 实现前端分页时,使用
requestIdleCallback进行节流处理 - 使用 Web Worker 处理数据切片
- 实现懒加载(仅加载当前页数据)
2. 安全风险
潜在的安全风险包括:
- XSS 攻击(通过
innerHTML插入恶意代码) - SQL 注入(如果涉及数据库查询)
- 跨站请求伪造(CSRF)
防范措施:
- 使用
textContent替代innerHTML - 使用参数化查询
- 验证用户输入
- 使用 CSRF Token
3. 代码可维护性
建议采用以下结构:
src/
├── components/
│ └── Pagination/
│ ├── index.js // 主逻辑
│ ├── styles.css // 样式
│ └── README.md // 使用说明
├── utils/
│ └── dataUtil.js // 数据处理工具
└── index.html // 主页面九、常见问题与踩坑
1. 分页控件不更新
常见原因:
- 没有正确绑定点击事件
currentPage变量未正确更新- 没有重新渲染表格内容
解决方案:
pageItem.on('click', function() {
settings.currentPage = i;
renderPage(); // 立即更新视图
});2. 分页按钮显示异常
常见原因:
- 数据源为空时未处理
- 页码计算错误
解决方案:
if (settings.dataSource.length === 0) {
$('#pagination').html('<div class="text-center">暂无数据</div>');
}3. 分页控件样式错乱
常见原因:
- 未正确引入 Bootstrap CSS
- 样式覆盖冲突
解决方案:
- 确保使用最新版本 Bootstrap
- 在 CSS 中使用
!important强制覆盖 - 使用 CSS 隔离
十、最佳实践
1. 推荐使用场景
- 中小型数据集(10w 以内)
- 需要统一分页样式
- 需要快速实现分页功能
- 不需要复杂的排序/过滤功能
2. 不推荐使用场景
- 大数据量场景(建议使用虚拟滚动)
- 需要复杂交互(建议使用分页库)
- 需要动态数据加载(建议使用分页服务端接口)
- 需要响应式布局(建议使用分页组件库)
3. 推荐方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 原生实现 | 灵活可控 | 代码冗余 |
| Bootstrap 分页 | 样式统一 | 功能单一 |
| 分页库(如 react-paginate) | 功能丰富 | 依赖复杂 |
| 虚拟滚动 | 高性能 | 实现复杂 |
十一、总结
通过 jQuery 和 Bootstrap 封装的表格分页组件,我们实现了:
- 简化分页逻辑
- 统一分页样式
- 提供统一 API 接口
- 支持动态数据加载
在实际开发中,这种封装方案适用于中小型数据集场景,但需要警惕大数据量时的性能瓶颈。通过合理使用分页组件,可以显著提升开发效率,同时保证代码的可维护性和可扩展性。对于更复杂的场景,建议结合虚拟滚动技术或专业的分页库进行深度优化。
评论已关闭