写在前面:

  有时候表格的需求就是奇奇怪怪的,最近要做的表格需要实现当紧挨着的记录的某一列的行元素内容相同,就将其合并。要是不是相同的就不合并。如果表格数据的顺序不需要被改变,这个样子是可以很简单就完成的(只需要计算出所有相同元素出现的次数即可,不需要考虑是否紧挨着),但是当可以改变排序的时候,这个时候就有点儿问题了。可能表述的有点儿不明白,下面具体看图描述问题吧。

  具体的需求,假设现在有三条记录,后台按照顺序x排好后传递给前台页面进行显示。

  页面拿到数据后将相同行进行合并后可以得到右边图的效果,但是如果现在在页面选择了一个排序按钮后,现在的排序被打乱了,又该怎样去实现合并?

  这里值得思考的是,后面每个列的最多的合并次数是基于前一个列的合并的次数来的,所以这里是个切入点,记录下第一列所有紧挨着的相同行内容出现的次数,然后遍历,去计算第二列所有紧挨着的相同行内容出现的次数,然后遍历,去计算第三列所有紧挨着的相同行内容出现的次数,依次下去。。。。。将每一列紧挨着的相同元素的次数都记录下来,然后拿到了这些次数,最后使用bootstrapTable自带的mergeCells方法去合并即可。越来越觉得数据结构以及算法重要性,最近太多写的程序都涉及到一些逻辑的算法,还是上学时要把这两个学好呀~~~~~~~

  2018.12.7晕死了晕死了,之前写的测出了bug,还是之前太大意了,又将代码修改了一下,花了三个小时才跟踪到问题,真的是晕死了。。。然后放在ie8上又出了问题,最后还是知道了问题的所在,完美的解决了。。。。。今天要请他们吃饭,目测是要大出血!!!!!!

  下面看看代码:

<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2018/6/20
Time: 14:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String scheme = request.getScheme();
String serverName = request.getServerName();
String contextPath = request.getContextPath();
int port = request.getServerPort();
//网站的访问跟路径
String baseURL = scheme + "://" + serverName + ":" + port
+ contextPath;
request.setAttribute("baseURL", baseURL);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<%--设置IE渲染方式(文档)默认为最高(这部分可以选择添加也可以不添加)--%>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>实现表格同名合并</title>
<!--图标样式-->
<link rel="stylesheet" type="text/css" href="${baseURL}/Bootstrap/bootstrap/css/bootstrap.min.css" />
<link href="${baseURL}/Bootstrap/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
<script src="${baseURL}/Bootstrap/bootstrap/assets/js/jquery-1.10.2.min.js"></script>
<script src="${baseURL}/Bootstrap/bootstrap/assets/js/bootstrap.min.js"></script>
<script src="${baseURL}/Bootstrap/bootstrap-table/bootstrap-table.js"></script>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="${baseURL}/Bootstrap/bootstrap/assets/js/html5shiv.js"></script>
<script src="${baseURL}/Bootstrap/bootstrap/assets/js/respond.min.js"></script>
<![endif]-->
<style type="text/css"> </style> </head>
<body>
<div>
<table id="table"></table>
</div>
</body> <script type="text/javascript"> $(function () {
//初始化Table
$('#table').bootstrapTable({
url: '${baseURL}/Views/cc.json',//请求后台的URL(*) 这里我用的是一个json文件
method: 'get',//请求方式(*)
toolbar: '#toolbar',//工具按钮用哪个容器
striped: true,//是否显示行间隔色
cache: false,//是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
pagination: true,//是否显示分页(*)
sortable: false,//是否启用排序
sortOrder: "asc",//排序方式
//queryParams: queryParams,//传递参数(*)
sidePagination: "server",//分页方式:client客户端分页,server服务端分页(*)
pageNumber: 1,//初始化加载第一页,默认第一页
pageSize: 10,//每页的记录行数(*)
pageList: [10, 25, 50, 100],//可供选择的每页的行数(*)
// search: true,//是否显示表格搜索,此搜索是客户端搜索,不会进服务端
contentType: "application/x-www-form-urlencoded",
strictSearch: true,
showColumns: true,//是否显示内容列下拉框
showRefresh: true,//是否显示刷新按钮
minimumCountColumns: 2,//最少允许的列数
clickToSelect: true,//是否启用点击选中行
//这里如果要固定表头的话 就把height开启
//height: 700,//行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度
width:'50%',
uniqueId: "id",//每一行的唯一标识,一般为主键列
showToggle: true,//是否显示详细视图和列表视图的切换按钮
cardView: false,//是否显示详细视图
detailView: false,//是否显示父子表
onLoadSuccess: function (data) {
//数据加载成功后 进行合并 这里我只是同名合并projName subProj phase 如果需要合并更多的字段 仿照添加对应的代码就可以了
mergeTable(data,"table");
},
columns: [
{
field: 'projName',
title: 'projName',
}, {
field: 'subProj',
title: 'subProj'
}, {
field: 'phase',
title: 'phase'
}, {
field: 'workItem',
title: 'workItem',
},
{
field: 'completion',
title: 'completion',
},
],
});
}); //全局变量 ***如果每次只是发送ajax请求对table进行局部更新,则每次要合并前前都应该清空这三个变量 不然全局变量会一值追加结果
var projNameCount="";
var subProjNameCount="";
var phaseCount=""; //合并表格
function mergeTable(data,tableId){
//每次合并表格前 都要将全局变量清空
projNameCount="";
subProjNameCount="";
phaseCount="";
mergeCells(data.rows,0,data.rows.length,"projName",$('#'+tableId));
//对projName,subProjName,phase的次数进行分割
//去掉末尾的逗号 有时候也可以不用去掉 还是去掉了我这里
projNameCount = projNameCount.substring(0,projNameCount.length-1);
subProjNameCount = subProjNameCount.substring(0,subProjNameCount.length-1);
phaseCount = phaseCount.substring(0,phaseCount.length-1);
//console.log(projNameCount+"+"+subProjNameCount+"+"+phaseCount);
var strArr1 = projNameCount.split(",");
var strArr2 = subProjNameCount.split(",");
var strArr3 = phaseCount.split(",");
//根据次数进行表格合并
//合并projName
var index = 0;
for(var i=0;i<strArr1.length;i++){
var count = strArr1[i] * 1;
$('#'+tableId).bootstrapTable('mergeCells',{index:index, field:"projName", colspan: 1, rowspan: count});
index += count;
}
//合并subProjName
var index = 0;
for(var i=0;i<strArr2.length;i++){
var count = strArr2[i] * 1;
$('#'+tableId).bootstrapTable('mergeCells',{index:index, field:"subProjName", colspan: 1, rowspan: count});
index += count;
}
//合并phaseName
var index = 0;
for(var i=0;i<strArr3.length;i++){
var count = strArr3[i] * 1;
$('#'+tableId).bootstrapTable('mergeCells',{index:index, field:"phaseName", colspan: 1, rowspan: count});
index += count;
}
} //排序后紧挨在一起 进行同名合并
/**
* 对于表格合并,首先要进行排序,即将同名的属性的记录排序紧挨在一起,这样才能最好的显示出合并想要的效果。
* 因为此方法是拿第一个数据与后面的数据依次比较,
* 例如,第一条记录的projName与第二条记录的projName来进行比较,两者相同,则继续第一条记录的projName与第三条记录的projName来进行比较,
* 当不相同时,记录下此projName对应的值出现的次数,然后再开始从第三条记录的projName与第四条记录的projName来进行比较,依次循环下去,记
* 录下相同内容的值出现的次数,到时候,再根据这些次数来进行合并
*
* 此方法主要是先拿到每个同名属性的值的相等次数,把次数利用全局变量存下来
*
* @param datas --表格数据,一般为表格的rows数据
* @param startIndex --开始下标
* @param size --从开始下标起,到size结束,遍历合并多少个
* @param fieldName --计算算哪个列
* @param target --table表格对象
*/
function mergeCells(datas,startIndex,size,fieldName,target) {
//console.log("startIndex:"+startIndex+"size:"+size+"---合并列:"+fieldName)
//声明一个数组计算相同属性值在data对象出现的次数和
//这里不能使用map,因为如果涉及到排序后,相同的属性并不是紧挨在一起,那么后面的次数会覆盖前面的次数,故这里用数组
var sortArr = new Array();
for (var i = startIndex; i < size ; i++) {
for (var j = i + 1; j < size; j++) {
if (datas[i][fieldName] != datas[j][fieldName]){
//相同属性值不同
if (j - i > 1) {
sortArr.push(j - i);
i = j - 1;
//如果是最后一个元素 把最后一个元素的次数也装进去
if(i == size-1-1){
sortArr.push(1);
}
}else{
sortArr.push(j - i);
//如果j是最后一个元素 把最后一个元素的次数装进去
if(j == size - 1){
sortArr.push(1);
}
}
break; }else {
//相同属性值相同 直到最后一次的时候才会装 否则在他们的值不同时再装进去
if (j == size - 1) {
sortArr.push(j - i+1);
//这里的赋值感觉有点多余 算了现就这个样子吧 不影响功能
i = j;
}
}
}
} //遍历数组,将值装追加到对应的字符串后面
for(var prop in sortArr){
/*这里在ie8上运行的时候 出现坑 最好遍历数组不要用for in 这里我用了就懒得换了
下面加上如果prop是indexOf就停止 就解决了ie8出现的问题*/
if(prop == "indexOf"){
continue;
}
if(fieldName == "projName"){
var count = sortArr[prop] * 1;
projNameCount += count +",";
} if(fieldName == "subProjName"){
var count = sortArr[prop] * 1;
subProjNameCount += count +",";
} if(fieldName == "phaseName"){
var count = sortArr[prop] * 1;
phaseCount += count +",";
}
} for(var prop in sortArr){
if(prop == "indexOf"){
continue;
}
if(fieldName == "projName"){
//console.log("进入projName--此时开始index-"+startIndex+"--结束index--"+(startIndex+sortArr[prop])*1);
startIndex = 0;
//subProjName每次进去的startIndex为前面次数的和
if(subProjNameCount.length>0){
//console.log("subProjNameCount-"+subProjNameCount);
var temp = subProjNameCount.substring(0,subProjNameCount.length-1);
var strArr1 = temp.split(",");
for(var i=0;i<strArr1.length;i++){
var count = strArr1[i] * 1;
startIndex += count;
}
} if(sortArr[prop] >1){
mergeCells(datas,startIndex,startIndex+sortArr[prop],"subProjName",target);
}else{
//当projName的次数为1就不进入循环
subProjNameCount +=1+",";
phaseCount +=1+",";
}
}
if(fieldName == "subProjName"){
startIndex = 0;
if(phaseCount.length>0){
//console.log("phaseCount-"+phaseCount);
var temp = phaseCount.substring(0,phaseCount.length-1);
//phaseCount = phaseCount + ",";
var strArr1 = temp.split(",");
for(var i=0;i<strArr1.length;i++){
var count = strArr1[i] * 1;
startIndex += count;
}
}
if(sortArr[prop] >1){
//console.log("进入subProj--此时开始index-"+startIndex+"--结束index--"+(startIndex+sortArr[prop])*1);
mergeCells(datas,startIndex,startIndex+sortArr[prop],"phaseName",target)
}else{
phaseCount +=1+",";
}
}
}
}
</script>
</html>

  上面就是完整的代码了,效果图如下:(此代码只需要计算projName,subProj,phase的合并就可以了,后面workitem不需要再合并了,因为后台查询的就是每一条workitem记录)

  其中对于bootstrap-table自带的合并单元格的方法,也是很好用的,也是基于此基础上才能完成。

$('#table').bootstrapTable('mergeCells',{index:index, field:"projName", colspan: 1, rowspan: count});

  参考连接:https://blog.csdn.net/qq_30641447/article/details/80772574

Bootstrap-table实现动态合并相同行(表格同名合并)的更多相关文章

  1. bootstrap table插件动态加载表头

    这篇文章主要为大家详细介绍了bootstrap table插件动态加载表头,具有一定的参考价值,感兴趣的小伙伴们可以参考一下   bootstrap的table属性已经很熟悉了,最近遇到一个问题,犹豫 ...

  2. easyui-datagrid合并相同行功能扩展

    //合并相同行$.extend($.fn.datagrid.methods, { autoMergeCells: function (jq, fields) { return jq.each(func ...

  3. 关于Bootstrap Table使用生成冻结窗格的表格

    参考资料 : <JS组件系列——Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案> <http://issues.wenzhixin.net.cn/bootst ...

  4. Bootstrap-table实现动态合并相同行

    Bootstrap-table  表格合并相同名字的列 @编写function() /** * 合并行 * @param data 原始数据(在服务端完成排序) * @param fieldName ...

  5. easyui datagrid 合并相同行

    $.extend($.fn.datagrid.methods, { autoMergeCells: function (jq, fields) { return jq.each(function () ...

  6. JS组件系列——表格组件神器:bootstrap table(二:父子表和行列调序)

    前言:上篇 JS组件系列——表格组件神器:bootstrap table 简单介绍了下Bootstrap Table的基础用法,没想到讨论还挺热烈的.有园友在评论中提到了父子表的用法,今天就结合Boo ...

  7. JS组件系列——表格组件神器:bootstrap table(三:终结篇,最后的干货福利)

    前言:前面介绍了两篇关于bootstrap table的基础用法,这章我们继续来看看它比较常用的一些功能,来个终结篇吧,毛爷爷告诉我们做事要有始有终~~bootstrap table这东西要想所有功能 ...

  8. JS组件系列——表格组件神器:bootstrap table

    前言:之前一直在忙着各种什么效果,殊不知最基础的Bootstrap Table用法都没有涉及,罪过,罪过.今天补起来吧.上午博主由零开始自己从头到尾使用了一遍Bootstrap Table ,遇到不少 ...

  9. 新的表格展示利器 Bootstrap Table Ⅱ

        上一篇文章介绍了Bootstrap Table的基本知识点和应用,本文针对上一篇文章中未解决的文件导出问题进行分析,同时介绍BootStrap Table的扩展功能,当行表格数据修改. 1.B ...

随机推荐

  1. 如何把SSL公钥和私钥转化为PFX格式

    1.登陆   https://myssl.com/cert_convert.html 2.原格式选择为 “PEM”,目标格式选择为 “PKCS12” 3.上传cer到 ”证书文件“,上传key到 ”私 ...

  2. Spring学习--引用其他Bean , 内部Bean

    引用其他Bean: 组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能 , 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用. 在 Bean 的配置文 ...

  3. HDU 2105 The Center of Gravity (数学)

    题目链接 Problem Description Everyone know the story that how Newton discovered the Universal Gravitatio ...

  4. POJ 2395 Out of Hay (prim)

    题目链接 Description The cows have run out of hay, a horrible event that must be remedied immediately. B ...

  5. thinkphp 导入微信小程序加密解密库

    第三方类库 第三方类库指除了 ThinkPHP 框架.应用项目类库之外的其他类库,一般由第三方系统或产品提供,如 Smarty.Zend 等系统的类库等. 前面使用自动加载或 import 方法导入的 ...

  6. 数据安全之MD5、SHA-1、CRC32区别

    crc32 — 计算一个字符串的 crc32 多项式 生成 string 参数的 32 位循环冗余校验码多项式……:这句话从英文翻译过来的,不正确,准确的说应该是这么理解: 以32位循环冗余校验多项式 ...

  7. hashlib,suprocess,configparser模块

    十 hashlib模块 1.什么叫hash:hash是一种算法,该算法接受传入的内容,经过运算得到一串hash值 2.hash值的特点是: 2.1 只要传入的内容一样,得到的hash值必然一样==== ...

  8. Bean利用Resource接口获取资源的几种方式

    Resources的类型 获取resource的方式(xml配置正常进行):

  9. [ Openstack ] Openstack-Mitaka 高可用之 Dashboard

    目录 Openstack-Mitaka 高可用之 概述    Openstack-Mitaka 高可用之 环境初始化    Openstack-Mitaka 高可用之 Mariadb-Galera集群 ...

  10. 图的遍历[DFS][BFS]

    #include<iostream> #include<iostream> #include<cstring> #include<queue> #inc ...