最近遇到一个需求:页面上的数据可能会有很多条,需要将数据分页展示在表格中。项目用的是 jQuery 和 Bootstrap,本来想直接用 bootstrapTable 插件,但是需要额外引入 js 文件、语言包等等,样式、语言翻译啥的都不太好做,索性还是决定参照这个,基于 jQuery 和 Bootstrap,自己实现一个简单版的。因为项目提供的后端接口直接将查询到的所有数据返回,所以这个分页实际上只是个假分页罢了,抓住关键点——当前页展示的数据与当前页码以及每页展示数量有关,其它的就好办了。先明确要实现的效果。

  1. 表头根据指定数据动态生成
  2. 可以修改每页展示的数据条数
  3. 要显示当前页相关信息,包括当前页码、当前页数据是第几条到第几条、数据总条数
  4. 表格提供切换页码操作,可以切换上一页、下一页、首页和末页
  5. 表格提供多选操作,可以选择某一条数据或选中多条数据以及全选、全不选

所以整个分页组件可以分为三大部分:选择每页展示条数的选择框、展示数据的表格(可以多选、可以操作)、底部显示当前页相关信息以及切换页码的按钮。html 以及 css 部分的代码如下,注意要引入 jQuery 以及 Bootstrap 相关的 js 和 css 文件。

<div class="table-box" id="tableList"><div class="per-page row"><div class="col-xs-4"><span>每页展示</span><div class="dropdown selectPageSize"><input type="hidden" class="pageSize" value="10"><button class="form-control dropdown-toggle" data-toggle="dropdown">10</button><ul class="dropdown-menu" role="menu"><li data-value="3"><label>3</label></li><li data-value="5"><label>5</label></li><li data-value="10"><label>10</label></li></ul></div></div></div><table class="table"data-multi-select="true"data-has-id="true"data-has-operate="true"data-operate-items="onlyDelete"><thead></thead><tbody></tbody></table><div class="table-footer row"><div class="col-xs-1"><input type="checkbox" class="selectAll"><span>全选</span></div><div class="col-xs-11"><span class="dataInfo"></span><ul class="pagination"><li><span class="startPage" aria-label="Start" aria-hidden="true">&laquo;</span></li><li><span class="prevPage" aria-label="Previous" aria-hidden="true">&lt;</span></li><li class="active"><span class="nowPage">1</span></li><li><span class="nextPage" aria-label="Next" aria-hidden="true">&gt;</span></li><li><span class="endPage" aria-label="End" aria-hidden="true">&raquo;</span></li></ul></div></div>
</div>
/* 整体的样式 */
.table-box {width: 80%;border-radius: 5px;margin: 20px auto;border: 1px solid #f2f2f2;
}
.per-page {margin: 15px -10px;
}
/* 选择框 */
.selectPageSize {display: inline-block;width: 50px;margin-left: 5px;
}
.dropdown-toggle {padding: 5px;height: 25px;line-height: 15px;
}
/* 选择框中的小三角 */
.dropdown-toggle::after {display: block;content: "";float: right;width: 0;height: 0;border-color: #FFFFFF transparent;border-style: solid;border-width: 4px 4px 0 4px;margin-top: 6px;border-top-color: #FFFFFF;
}
/* 下拉列表 */
.dropdown-menu {width: 100%;min-width: unset;padding: 0;overflow-y: auto;
}
.dropdown-menu > li > label {width: 100%;padding: 2px 10px;margin: 0;font-weight: 400;text-align: center;
}
/* 鼠标悬停在选择框某一项 */
.dropdown-menu > li > label:hover {color: #FFFFFF;background-color: #0066cc;
}
/* 表头 */
.table > thead > tr > th {text-align: center;font-weight: normal;line-height: 34px;border: none;background-color: #f2f2f2;
}
/* 可多选表格的多选框样式 */
.table[data-multi-select="true"] > thead > tr > th:first-child {width: 30px;line-height: 30px;
}
/* 单元格样式 */
.table > tbody > tr > td {text-align: center;border: none;line-height: 24px;
}
.table > tbody > tr:last-child {border-bottom: 1px solid #f2f2f2;
}
/* 可操作的表格 */
.table[data-has-operate="true"] > tbody .deleteThis {color: orange;cursor: pointer;
}
.table[data-has-operate="true"] > tbody .editThis {color: #0066cc;cursor: pointer;
}
.table-footer {margin: 15px -15px;
}
/* 可多选的表格要在表头以及表格下方提供多选框 */
.table[data-multi-select="true"] + .row > div:first-child {display: inline-flex;align-items: center;justify-content: flex-start;padding-left: 25px;
}
.table[data-multi-select="true"] + .row > div:first-child > input {margin: 0 5px 0 0;
}
.table[data-multi-select="true"] + .row > div:first-child > span {text-align: center;flex: 1;
}
.table-footer > div:last-child {display: inline-flex;align-items: center;justify-content: flex-end;
}
/* 分页部分的样式 */
.pagination {margin: 0 10px;
}
.pagination > li > span {padding: 0 10px;margin: 0 3px;border-radius: 4px;cursor: pointer;
}
.pagination > li > span:hover,
.pagination > li > span:focus {background-color: #FFFFFF;
}
.dropdown-toggle,
.dropdown-menu > li > label:hover,
.pagination > li.active > span,
.pagination > li.active > span:hover,
.pagination > li.active > span:focus {color: #FFFFFF;border-color: #0066cc;background-color: #0066cc;
}

组件基本的结构和样式已经完成,接下来是最关键的 js 部分。针对上面列出的5个效果,来一步步分析如何通过 js 实现。首先肯定要获取我们后续要操作的对象,基于 jQuery 封装一个方法,代码如下。

(function($){$.fn.initTable = function(data, isFirst, thName) {// data: 表格需要展示的所有数据 isFirst: 需要添加表头、绑定事件等 thName: 表头的名称isFirst = isFirst || 0;// nPanel: 当前表格组件对象var nPanel = this;// pageSize: 每页展示条数var pageSize = nPanel.find(".pageSize").val();// total: 数据总条数var total = data.length;// tPage: 页面总数var tPage = Math.ceil(total/perPage);// nPage: 当前页数var nPage = parseInt(nPanel.find(".nowPage").text());var table = nPanel.find(".table");// multi: 表格数据是否可多选var multi = table.attr("data-multi-select") === "true" ? 1 : 0;// hasID: 表是否有序号列var hasID = table.attr("data-has-id") === "true" ? 1 : 0;// hasOp: 表是否有操作列var hasOp = table.attr("data-has-operate") === "true" ? 1 : 0;// operate: 表的操作列有哪些操作var operate = table.attr("data-operate-items") || "all";}
})(jQuery);

先考虑如何生成表头,需要传入一个数组 thName,存放表头的名称,并非每次调用 initTable 方法时都需要重新生成表头以及给元素绑定事件,通过参数 isFirst 来判断,如果是第一次调用 initTable 方法则需要生成表头、给选择每页条数、多选框等绑定事件。在给每行的元素(比如多选框)绑定事件时要注意,因为表格每一行都是动态生成的,现在还获取不到目标元素,无法直接绑定事件,所以采用事件委托的方式,通过 jQuery 实现起来还是很简单的。对于页码切换的事件绑定则需要在每次调用 initTable 方法的时候重新绑定,否则还是基于最初的数据进行更改。代码如下。

// 首次调用该方法,添加表头、绑定事件、应用样式等
if (isFirst === 1) {if (multi) {nPanel.find(".table-footer").find("div:first-child").show();nPanel.find(".table-footer").find("div:last-child").removeClass("col-xs-offset-1");// 选中所有条目nPanel.on("click", ".selectAll", function(){nPanel.find(":checkbox:not(:disabled)").prop("checked", $(this).is(":checked"));});// 当全选按钮被选中时,取消选中表格任意一条的同时取消选中全选table.on("click", ":checkbox:not(:disabled)", function(){if (nPanel.find(".selectAll").is(":checked") && !$(this).is(":checked")) {nPanel.find(".selectAll").prop("checked", false);}});} else {nPanel.find(".table-footer").find("div:first-child").hide();nPanel.find(".table-footer").find("div:last-child").addClass("col-xs-offset-1");}// 根据传入的表头名称,动态生成表头// 因为表头只有一行,就可以直接生成一个 tr 元素,不需要文档碎片var thEle = $("<tr></tr>");thName.forEach(function(v, i){if (i === 0) {// 表格是否可多选if (multi) {thEle.append("<th><input type='checkbox' class='selectAll'></th>");}// 表格是否有序号if (hasID) {thEle.append("<th>序号</th>");}}thEle.append("<th>"+v+"</th>");// 表格是否可操作if (i === thName.length-1 && hasOp) {thEle.append("<th>操作</th>");}});table.find("thead").append(thEle);// 选择每页展示数量$(".dropdown-menu").on("click", "li", function(){var inputBox = $(this).parent().siblings("input");var nowValue = $(this).attr("data-value");var nowText = $(this).find("label").text();if (nowValue !== inputBox.val()) {// 新值与旧值对比,发生了变化才更改$(this).parent().prev().text(nowText);inputBox.val(nowValue);// 由于直接修改 input 值不会触发 change 事件,因此使用 trigger 方法触发自定义事件 changed,并将当前值传给它inputBox.trigger("changed", nowValue);}});
} else {// 不是第一次调用则将需要先移除之前的事件,重新绑定事件$(".pageSize").off("changed");$(".startPage, .prevPage, .endPage, .nextPage").off("click");
}// 监听自定义事件 changed,更新表格当前页数据
$(".pageSize").on("changed", function(e, v){pageSize = v;tPage = Math.ceil(total/pageSize);nPage = nPage > tPage ? tPage : nPage;changeRange();
});// 跳转到第一页或上一页
$(".startPage, .prevPage").on("click", function(){if (nPage > 1) {nPage = $(this).hasClass("startPage") ? 1 : nPage-1;changeRange();} else {alert("当前已经在第一页");}
});// 跳转到最后一页或下一页
$(".endPage, .nextPage").on("click", function(){if (nPage < tPage) {nPage = $(this).hasClass("endPage") ? tPage : nPage+1;changeRange();} else {alert("当前已经在最后一页");}
});

现在表头有了,数据也有了,接下来要将它们放到表格。因为在修改页码以及每页展示数量时,都需要重新渲染表格主体内容,所以将这部分代码放到 changeRange 函数中方便直接调用。思路大概是这样:已知当前页码和每页展示数量,就可以知道当前页需要展示的数据是哪些(数组中第几条到第几条的数据)。接下来就是dom操作了,遍历当前页的数据,每一条数据对应表格的一行(tr),具体的数据项放到对应单元格(td),遍历完之后利用文档碎片一次性插入到 tbody 中完成显示。代码如下。

// 修改表格主体内容
function changeRange(){// 清空表格主体部分table.find("tbody").empty();// 更新当前页码nPanel.find(".nowPage").text(nPage);// 当前页第一条数据在数组中的索引号var pageStart = (nPage-1)*pageSize;// 当前页最后一条数据的序号var pageEnd = nPage*pageSize > total ? total : nPage*pageSize;// 取消选定所有多选框if (multi) {nPanel.find(":checkbox").prop("checked", false);}// 更新当前页的信息显示nPanel.find(".dataInfo").text("第"+((total === 0) ? 0 : (pageStart+1))+"到第"+pageEnd+"条,总共"+total+"条");// 利用碎片化文档,避免频繁操作 DOMvar dom = document.createDocumentFragment();if (total > 0) {// 获取当前页的数据,利用数组的 slice 方法截取数据片段var nowPageData = data.slice(pageStart, pageEnd);// 遍历数组,将数据放到对应表格 td 中,得到表格主体 tbody 的内容nowPageData.forEach(function(v, i){var trEle = $("<tr></tr>");Object.keys(v).forEach(function(k, j){if (j == 0 && hasID) {trEle.append("<td>"+(pageStart+1+i)+"</td>");}trEle.append("<td>"+v[k]+"</td>");});// 表格可以多选,添加多选框if (multi) {trEle.prepend("<td><input type='checkbox'></td>");}// 表格可以操作,添加操作项if (hasOp) {if (operate === "onlyDelete") {// 操作项只有删除trEle.append("<td><span class='deleteThis'>删除</span></td>");} else if (operate === "all") {// 默认操作项有编辑和删除trEle.append("<td><span class='editThis'>编辑</span>&nbsp;|&nbsp;<span class='deleteThis'>删除</span></td>");}}dom.appendChild(trEle[0]);});} else if (total === 0) {var thNum = table.find("thead").find("th").length;dom.appendChild($("<tr><td colspan="+thNum+">没有数据</td></tr>")[0]);}// 将存放了表格主体内容的碎片化文档放到 DOM 中,完成一次性更新表格table.find("tbody").append(dom);
}

整体 js 代码如下。

(function($){$.fn.initTable = function(data, isFirst, thName) {// data: 表格需要展示的所有数据 isFirst: 需要添加表头、绑定事件等 thName: 表头的名称isFirst = isFirst || 0;// nPanel: 当前表格组件对象var nPanel = this;// pageSize: 每页展示条数var pageSize = nPanel.find(".pageSize").val();// total: 数据总条数var total = data.length;// tPage: 页面总数var tPage = Math.ceil(total/pageSize);// nPage: 当前页数var nPage = parseInt(nPanel.find(".nowPage").text());// 表格对象var table = nPanel.find(".table");// multi: 表格数据是否可多选var multi = table.attr("data-multi-select") === "true" ? 1 : 0;// hasID: 表是否有序号列var hasID = table.attr("data-has-id") === "true" ? 1 : 0;// hasOp: 表是否有操作列var hasOp = table.attr("data-has-operate") === "true" ? 1 : 0;// operate: 表的操作列有哪些操作var operate = table.attr("data-operate-items") || "all";// 首次调用该方法,添加表头、绑定事件、应用样式等if (isFirst === 1) {if (multi) {nPanel.find(".table-footer").find("div:first-child").show();nPanel.find(".table-footer").find("div:last-child").removeClass("col-xs-offset-1");// 选中所有条目nPanel.on("click", ".selectAll", function(){nPanel.find(":checkbox:not(:disabled)").prop("checked", $(this).is(":checked"));});// 当全选按钮被选中时,取消选中任意一条规则的同时取消选中全选table.on("click", ":checkbox:not(:disabled)", function(){if (nPanel.find(".selectAll").is(":checked") && !$(this).is(":checked")) {nPanel.find(".selectAll").prop("checked", false);}});} else {nPanel.find(".table-footer").find("div:first-child").hide();nPanel.find(".table-footer").find("div:last-child").addClass("col-xs-offset-1");}// 生成表头,获取对象的属性名var thEle = $("<tr></tr>");thName.forEach(function(v, i){if (i === 0) {if (multi) {thEle.append("<th><input type='checkbox' class='selectAll'></th>");}if (hasID) {thEle.append("<th>序号</th>");}}thEle.append("<th>"+v+"</th>");if (i === thName.length-1 && hasOp) {thEle.append("<th>操作</th>");}});table.find("thead").append(thEle);table.find("thead").attr("data-number", thName.length+multi+hasID+hasOp);// 选择每页展示数量$(".dropdown-menu").on("click", "li", function(){var inputBox = $(this).parent().siblings("input");var nowValue = $(this).attr("data-value");var nowText = $(this).find("label").text();if (nowValue !== inputBox.val()) {// 新值与旧值对比,发生了变化才更改$(this).parent().prev().text(nowText);inputBox.val(nowValue);// 由于val方法直接修改input值不会触发change事件,因此使用 trigger 方法触发自定义事件 changed,并将当前值传给它inputBox.trigger("changed", nowValue);}});}// 监听自定义事件 changed,更新表格当前页数据nPanel.on("changed", ".pageSize", function(e, v){pageSize = v;tPage = Math.ceil(total/pageSize);if (nPage > tPage) {nPage = tPage;}changeRange();});// 跳转到第一页或上一页nPanel.on("click", ".startPage, .prevPage", function(){if (nPage > 1) {nPage = $(this).hasClass("startPage") ? 1 : nPage-1;changeRange();} else {alert("当前已经在第一页");}});// 跳转到最后一页或下一页nPanel.on("click", ".endPage, .nextPage", function(){if (nPage < tPage) {nPage = $(this).hasClass("endPage") ? tPage : nPage+1;changeRange();} else {alert("当前已经在最后一页");}});changeRange();// 获取指定页的数据function changeRange(){// 清空表格主体部分table.find("tbody").empty();// 更新当前页码nPanel.find(".nowPage").text(nPage);// 当前页第一条数据在数组中的索引号var pageStart = (nPage-1)*pageSize;// 当前页最后一条数据的序号var pageEnd = nPage*pageSize > total ? total : nPage*pageSize;// 取消任意多选框的选择if (multi) {nPanel.find(":checkbox").prop("checked", false);}// 更新当前页的信息显示nPanel.find(".dataInfo").text("第"+((total === 0) ? 0 : (pageStart+1))+"到第"+pageEnd+"条,总共"+total+"条");// 利用碎片化文档,避免频繁操作 DOMvar dom = document.createDocumentFragment();if (total > 0) {// 获取当前页的数据,利用数组的 slice 方法截取数据片段var nowPageData = data.slice(pageStart, pageEnd);// 遍历数组,将数据放到对应表格 td 中,得到表格主体 tbody 的内容nowPageData.forEach(function(v, i){var trEle = $("<tr data-index="+(pageStart+i)+"></tr>");Object.keys(v).forEach(function(k, j){if (j == 0 && hasID) {trEle.append("<td>"+(pageStart+1+i)+"</td>");}trEle.append("<td>"+v[k]+"</td>");});// 表格可以多选,添加多选框if (multi) {trEle.prepend("<td><input type='checkbox'></td>");}// 表格可以操作,添加操作项if (hasOp) {if (operate === "onlyDelete") {// 操作项只有删除trEle.append("<td><span class='deleteThis'>删除</span></td>");} else if (operate === "all") {// 默认操作项有编辑和删除trEle.append("<td><span class='editThis'>编辑</span>&nbsp;|&nbsp;<span class='deleteThis'>删除</span></td>");}}dom.appendChild(trEle[0]);});} else if (total === 0) {var thNum = table.find("thead").find("th").length;dom.appendChild($("<tr><td colspan="+thNum+">没有数据</td></tr>")[0]);}// 将存放了表格主体内容的碎片化文档放到 DOM 中,完成一次性更新表格table.find("tbody").append(dom);}}
})(jQuery);

现在放一些数据,添加一个按钮删除第一行数据,展示一下效果吧

var tableData = [{name: 'Alice',mark1: 90,mark2: 89,mark3: 100},{name: 'Bob',mark1: 80,mark2: 90,mark3: 90},{name: 'Cindy',mark1: 82,mark2: 86,mark3: 84},{name: 'Daisy',mark1: 88,mark2: 79,mark3: 80},{name: 'Frack',mark1: 72,mark2: 60,mark3: 70},{name: 'Daniel',mark1: 62,mark2: 67,mark3: 60}
]
$("#tableList").initTable(tableData, 1, ["姓名", "语文", "数学", "英语"]);$("#deleteFirst").on("click", function(){tableData.splice(0, 1);$("#tableList").initTable(tableData);
});


如果对你有用,麻烦点个赞~有需要改进的地方,也欢迎在评论区留言!

基于 jQuery 与 Bootstrap 简单封装一个表格分页的组件相关推荐

  1. 基于jquery的bootstrap在线文本编辑器插件Summernote (转)

    Summernote是一个基于jquery的bootstrap超级简单WYSIWYG在线编辑器.Summernote非常的轻量级,大小只有30KB,支持Safari,Chrome,Firefox.Op ...

  2. 基于jquery的bootstrap在线文本编辑器插件Summernote

    Summernote是一个基于jquery的bootstrap超级简单WYSIWYG在线编辑器.Summernote非常的轻量级,大小只有30KB,支持Safari,Chrome,Firefox.Op ...

  3. node php知乎,基于jQuery和Bootstrap框架实现仿知乎前端动态列表效果

    最近基于jQuery和Bootstrap框架实现了一个仿知乎动态列表的前端效果,基本实现了和知乎动态列表相同的效果.如下: 1.基本列表项 2.列表项全文展开.折叠(图中为展开第一项) 3.评论项展开 ...

  4. bootstrap 轮播控制时间_【前端冷知识】如何封装一个图片轮播组件

    组件封装是一个前端工程师进阶的必经之路.组件封装是指Web页面上抽出来一个个包含模版(HTML).功能(Javascript)和样式(CSS)的单元.所以,今天的内容,我们将带你了解组件封装的开发思路 ...

  5. 第十一篇: 使用ElementUi 卡片封装一个季度选择器公共组件,可直接使用

    本篇主要内容:ElementUi 只提供了时间.日历等选择器,没有提供季度选择器,但在开发中报表的时候用到了季度选择器.需要换切换多种类型(年报.月报.季报), 于是封装一个季度公共组件,大家可按需修 ...

  6. 基于JQuery 改造bootstrap模态框拖动功能

    看不爽现有的bootstrap拖动实现,自己也手痒,就自己写了一个拖动处理. PS:其他实现拖动方法 http://www.gbtags.com/gb/rtreplayerpreview/230.ht ...

  7. 基于jquery,bootstrap数据验证插件bootstrapValidator 教程

    ootstrap:能够增加兼容性的强大框架. 因为项目需要数据验证,看bootstrapValidator 还不错,就上手一直,完美兼容,话不多说. 需要引用css: bootstrap.min.cs ...

  8. 【转】基于jquery,bootstrap数据验证插件bootstrapValidator 教程

    bootstrap:能够增加兼容性的强大框架. 因为项目需要数据验证,看bootstrapValidator 还不错,就上手一直,完美兼容,话不多说. 需要引用css: bootstrap.min.c ...

  9. 通用分页 (基于jquery、bootstrap)

    基于bootstrap的"通用分页"v2.0(有人用的话,我可以升级) 实现: 1.同一个页面下,多个分页条互不干扰. 2.配置.使用方便. 3.通过配置.修改容器的属性(page ...

最新文章

  1. JavaScript实现kruskal克鲁斯卡尔算法(附完整源码)
  2. QT的QScopedPointer类的使用
  3. ubuntu19.10安装codeblocks20.03
  4. SAP 电商云 Spartacus UI 的交货模式 Delivery Mode 设计
  5. exfat分配单元大小选多少_安防监控摄像机视角大小和镜头毫米数的基础知识!...
  6. CSS样式引入方式和部分CSS样式的设置
  7. sed 删除行首空格
  8. trueOS能装linux软件,GhostBSD 19.09 发布,使用来自TrueOS软件包
  9. java判断数组值类型,判断(1分) Java语言中的数组元素只能是基本数据类型而不能为对象类型。...
  10. 2021“华为杯”第十八届中国研究生数学建模竞赛有感
  11. python如何设置清华镜像源
  12. package.json文件指南
  13. Stata新命令:psestimate - 倾向得分匹配中协变量的筛选
  14. 使用虚拟机备份软件备份VMware vSphere虚拟机
  15. Docker学习之六:基于Dockerfile构建镜像
  16. 探索Franka Emika 机器人丨Powertool和Franka world的作用
  17. 视频回顾|Pulsar Summit Asia 2021,案例、运维、生态干货不断
  18. 可视化第一部分(简单的图形)
  19. Python自学笔记10:实操案例七(根据星座测试性格特点、模拟12306火车订票下单)
  20. 牛客网 KY11 二叉树遍历

热门文章

  1. 资料分享|kafka学习秘籍
  2. 《成为学习高手》小记
  3. Apache配置(Apache与PHP联系)
  4. 蓝桥杯校内模拟赛_C++组
  5. hfss和python接口_【技术分享】python和HFSS联合仿真微带天线的教程
  6. 网络空间安全数学基础部分证明,筛法、贝祖等式的编程实现。
  7. 如何保证按时上床睡觉?
  8. oracle 如何导入txt,Oracle中导入TXT并进行处理
  9. 刷脸支付的数字化助力商户无人化收银
  10. 蓝桥杯.第几个幸运数字(数学_因子)