一、最终效果图
工作中想用如图的方式去展示数据,虽然网上也有其它人写的相关插件,但是几乎都是一次性请求好数据并且不支持分页,不符合项目需求,所以就自己改了个,尽量避免动原插件的既有功能,当点击行前的折叠图标时,会通过ajax从后台调取数据并插入到表格中。
1、修改 BootstrapTable.prototype.initHeader 函数
/* 2018.01.10 为树域td添加class start */
var tempClass='';
if(that.options.treeView && column['field']===that.options.treeField){
tempClass=column['class']+' tree-field ';
}else{
tempClass=column['class'];
}
var text = '',
halign = '', // header align style
align = '', // body align style
style = '',
class_ = sprintf(' class="%s"', tempClass),
order = that.options.sortOrder || column.order,
unitWidth = 'px',
width = column.width;
/* 2018.01.10 为树域td添加class end */
2、修改 BootstrapTable.prototype.initRow 函数
/* 2018.01.10 表格树DOM结构 start */
var content=value;
if (that.options.treeView && column.field == that.options.treeField) {
var tempIsLastChild=$.extend(true,[],item.isLastChild);
var indent='',indentCount=0,treeRootLevel,treeMaxLevel,
selfIsLastChild=(tempIsLastChild.pop())?' tree-branch-last':'',
iconStatus=item.isExpand?' tree-expand':' tree-collapse';
// 对参数配置进行校验
if (that.options.treeRootLevel===undefined) {
treeRootLevel=data[0][that.options.treeLevelField]||0;
$.each(data,function(_index,v){
v[that.options.parentId]=v[that.options.parentId]||'';
treeRootLevel=Math.min(treeRootLevel,v[that.options.treeLevelField]);
});
}else{
treeRootLevel=parseInt(that.options.treeRootLevel);
}
// 防止 treeRootLevel 为非数字的情况
treeRootLevel=treeRootLevel||0;
treeMaxLevel=that.options.treeMaxLevel||Infinity;
item[that.options.treeParentLevelField]=item[that.options.treeParentLevelField]||treeRootLevel;
// 结构树的html
indent='<div class="tree-indent">';
if(item[that.options.parentId]||that.options.treeRootLevel!==undefined){// 绘制数据前的树结构线
for(var _index=treeRootLevel;_index<=item[that.options.treeParentLevelField];_index++){
indentCount++;
if (tempIsLastChild.shift()) {
indent+='<div class="tree-branch-101 tree-branch-last-child"></div>';
}else{
indent+='<div class="tree-branch-101"></div>';
}
}
}
if(item[that.options.treeLevelField]<treeMaxLevel){// 当前td数据是否还有下级
indentCount++;
indent+='<div class="tree-icon-wrapper tree-icon-branch-100 tree-icon-branch-001'+selfIsLastChild+'">'
+'<span class="tree-icon-branch-010 tree-icon treefont'+iconStatus+'"></span>'
+'</div>';
}else{
indentCount++;
indent+='<div class="tree-icon-wrapper tree-branch-101 tree-branch-010'+selfIsLastChild+'"></div>';
}
indent+='</div>';
// 表格数据及缩进
content='<div class="tree-content text-left" style="padding-left:'+(32*indentCount)+'px">'+value+'</div>';
}
text = that.options.cardView ? ['<div class="card-view">',
that.options.showHeader ? sprintf('<span class="title" %s>%s</span>', style,
getPropertyFromOther(that.columns, 'field', 'title', field)) : '',
sprintf('<span class="value">%s</span>', value),
'</div>'
].join('') : [sprintf('<td%s %s %s %s %s %s %s>',
id_, class_, style, data_, rowspan_, colspan_, title_),
indent,
content,
'</td>'
].join('');
/* 2018.01.10 表格树DOM结构 end */
3、修改 BootstrapTable.prototype.initBody 函数
// 在函数头部的循环中为每个节点增加isLastChild属性
for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
var item = data[i];
/* 2018.01.11 设置节点是否是最后一个 start */
if (that.options.treeView && data.length>0) {
if (!item.isLastChild) {
item.isLastChild=[];
if (i==this.pageTo-1) {
item.isLastChild.push(true);
}else{
item.isLastChild.push(false);
}
}
}
/* 2018.01.11 设置节点是否是最后一个 end */
var tr = this.initRow(item, i, data, trFragments);
hasTr = hasTr || !!tr;
if (tr&&tr!==true) {
trFragments.append(tr);
}
}
/* 2018.01.10 展开和折叠表格树事件绑定 start */
this.$body.find('> tr[data-index] > td .tree-icon').off('click').on('click', function (e) {
e.stopPropagation();
var $this = $(this),
$tr = $this.closest('tr'),
index = $tr.data('index'),
row = data[index];
var icon = $(this);
// 给被点击的行数据添加一个isExpand字段,记录它的“展开/折叠”状态
row.isExpand=!row.isExpand;
// 处理展开和折叠事件
if (icon.hasClass('tree-expand')) {
// 梳理需要折叠的tr行号范围,parentId为父节点的Id
var start=index;
if (row.isLastChild[row.isLastChild.length-1]) {
for (var i = index+1; i <data.length; i++) {
if (row[that.options.treeId] == data[i][that.options.parentId]) {
start=i;
}
}
if (data[start].isExpand) {
that.$body.find('> tr:eq('+start+') .tree-icon').click();
}
}else{
for (var i = index+1; i <data.length; i++) {
if (row[that.options.parentId] == data[i][that.options.parentId]) {
start=i-1;
break;
}
}
}
// 删除被折叠掉的tr行
for (var i = start; i >index; i--) {
data.splice(i,1);
}
} else {
// 展开子节点时,首先通过 getChild 函数获取子节点(这里假设是同步ajax请求,想要异步可适当调整)
var child=that.options.getChild(index, that.options.treeId);
if (child.length>0) {
child[0].isLastChild=true;
}
// 将子节点循环插入到当前节点后面
$.each(child, function (i, v) {
// 设置该行tree-field中的所有辅助线是否是同级最后一个,以便区别样式
v.isLastChild=$.extend(true,[],row.isLastChild);
if (i===0) {
v.isLastChild.push(true);
}else{
v.isLastChild.push(false);
}
if (row[that.options.treeId] == v[that.options.parentId]) {
data.splice(index+1,0,v);
}
});
}
// 重绘页面表格
that.initBody(true);
});
/* 2018.01.10 展开和折叠表格树事件绑定 end */
4、iconfont及css样式
增加了少许样式和字体,较简单,详见代码。
三、后记1、目前 getChild 函数获取数据时,还只支持同步请求,后续将改为支持异步;
2、代码及DEMO
点击查看更多内容
2人点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦