树表格,表格树,就是可以像菜单一样折叠展开的表格。对于具有上下级关系的数据,用表格树展示颇为直观方便。
最近对 ztree、ligerGrid、dataTables三个插件进行了一番研究。主要对比了它们对于各列各行数据的样式、逻辑的可控程度、灵活程度。
首先声明一下:在本文中,能进行伸缩有层级关系的列称为主列,其他称为从列,如下图
本文没有列出全部代码,只有部分片段,需要完整代码可前往https://gitee.com/willbebetter/table_tree_demo免费下载
样式比较丑,如果真要用的话,相信各位朋友可以写出自己满意的样式
下面开始正题
先看 demo 吧
1)可以给主列加样式,需设置 nameIsHTML 为 true,并且我试了 < a > 和 < div >标签是会解析出问题的,从列可以用任意标签。
2)因为主列是直接解析数据展现出来的,我没找到可以控制主列的显示逻辑的方法,比如可写个判断,主列的地区全部显示黑色,但是企业显示蓝色(这种效果可以通过在每个对象name属性加上一个class来控制)。从列是可以的,比如本例中判断电话是否为空,分别处理。
3)主列也没办法单独绑定click事件,可以用回调函数 onClick,但是这样的话,绑定的是整行,无论点该行的哪里,都会触发该事件。从列可以通过嵌入的html给单独的列进行绑定。
初始化表头
//初始化列表
zTreeNodes = data;
//初始化树
var treeObj = $.fn.zTree.init($("#dataTree"), setting, zTreeNodes);
// treeObj.expandAll(true); //展开/折叠所有节点
//添加表头
var li_head = ' 企业名称企业地址联系人' +
'联系方式操作';
var rows = $("#dataTree").find('li');
if (rows.length > 0) {
rows.eq(0).before(li_head)
} else {
$("#dataTree").append(li_head);
$("#dataTree").append('无符合条件数据 ')
}
参数设置
var zTreeNodes;
var setting = {
view: {
showLine: false,
showIcon: false,
nameIsHTML: true, //为了给主列搞点花样,把这个属性找出来了,功能如同属性名,把主列属性值解析为html,默认为false
//但是不能使用和标签,会和插件冲突。我测试中用的是,但是好像不能用class和id绑定事件
addDiyDom: addDiyDom //自定义节点显示方式
},
data: {
simpleData: {
enable: true
},
key: {
name: "name", //指定主列的属性,默认为 name
url: "baiduUrl" //指定跳转路径属性,单击触发,单机该行的任意单元格都可触发,不管有无数据;默认是对象中的url属性
}
},
callback: {
//onClick: dblClick
onDblClick: dblClick //这里的单击和双击都是整行生效的,该行的任意地方都可触发,不管有无数据;
}
};
/**
* 自定义DOM节点
*/
function addDiyDom(treeId, treeNode) {
var spaceWidth = 15;
var liObj = $("#" + treeNode.tId);
var aObj = $("#" + treeNode.tId + "_a");
var switchObj = $("#" + treeNode.tId + "_switch");
var icoObj = $("#" + treeNode.tId + "_ico");
var spanObj = $("#" + treeNode.tId + "_span");
aObj.attr('title', '');
aObj.append('');
var div = $(liObj).find('div').eq(0);
switchObj.remove();
spanObj.remove();
icoObj.remove();
div.append(switchObj);
div.append(spanObj);
var spaceStr = "";
switchObj.before(spaceStr);
//这里自定义的都是 从列的样式和逻辑,
var editStr = '';
editStr += '';
editStr += '' + (treeNode.headMan == null ? ' ' : treeNode.headMan ) + '';
if(treeNode.tel == null){
editStr += ' ';
}else{
editStr += '+ treeNode.tel +'" class="btnstyle" οnclick="btntest()" />';
}
editStr += '' + formatHandle(treeNode) + '';
aObj.append(editStr);
}
数据格式
var data = [
{ name: '北京市', isArea: true,
children: [
{ name: '海淀区', isArea: true, children:
[
{ isArea: false, name: '北京海淀科技有限公司', address:"北京海淀xx路1号", headMan:"张三", tel:"15910101234" },
{ isArea: false, name: '北京海淀软件测试有限公司', address:"北京海淀xx路10号", headMan:"李四", tel:"15209094321" }
]
},
{ name: '西城区', isArea: true, children:
[
{ isArea: false, name: '北京西城科技有限公司', address:"北京西城xx路1号", headMan:"王五", tel:"13511112222" }
]
},
{ name: '丰台区', isArea: true}
] },
{ name: '广东省', isArea: true, children: [
{ name: '广州市', isArea: true, children:
[
//使用 标签,这个信息到这个表格的外面了
{ isArea: false, name: "广东广州科技有限公司", address:"广东广州xx路1号", headMan:"赵六", tel:"13622226666" }
]
},
{ name: '深圳市', isArea: true }
] },
//下面是没有 children 属性的数据格式,需要 id 和 pid
{"id":"jxs","pId":"onull","name":"江西省","tel":null,"open":true,"isArea":true},
{"id":"ncs","pId":"jxs","name":"南昌市","tel":null,"open":true,"isArea":true},
{"id":"com1","pId":"ncs","name":"江西南昌科技有限公司","address":"江西南昌xx路101号","headMan":"xiao","tel":"15812345678","isArea":false},
{"id":"gzs","pId":"jxs","name":"赣州市","tel":null,"isArea":true,"baiduUrl":"https://www.baidu.com"},
// name 用了 标签,该行直接不显示了
{"id":"hns","pId":"onull","name":"湖南省","tel":null,"isArea":true}
];
dataTables
1)不管主列还是从列,甚至最前面的图标,都是单独的列,可以进行样式和逻辑的控制,绑定事件也很轻松,相当灵活。
2)有一个不太好的地方是,因为图标是单独的一列,显得与主列名称相隔太远,无论层级多么深入,最里层的图标都会在最外层主列名称的左边,显得很不自然。
var dataTable;
$(function() {
dataTable = $('#treetable').DataTable(
{
/**
l - Length changing 改变每页显示多少条数据的控件
f - Filtering input 即时搜索框控件
t - The Table 表格本身
i - Information 表格相关信息控件
p - Pagination 分页控件
r - processing 加载等待显示信息
**/
"dom" : "tr",
"ordering" : false, //禁用排序
"processing" : true,
"serverSide" : true,
"ajax" : {
"url" : "../static/json/dataTablesData.json",
},
'treeGrid' : {
'left' : 20, //主列的缩进
'expandAll' : true, //是否默认展开 true 是
//'expandIcon': ' + ',
//'collapseIcon': ' - '
// 注意:包裹图标标签的 标签不能少,否则子节点缩进格式会有问题
'expandIcon' : '',
'collapseIcon' : ''
},
"columns" : [
{
className : 'treegrid-control',
data : function(item) {
if (item.children != null&& item.children.length > 0) {
return '';
}
return '';
}
},
// 表格的每一列样式都可以用 className 来渲染
// 每一列的数据表现形式、逻辑都可用函数实现,非常灵活
// {
// "data" : "name"
// },
{
className : 'diyclass',
data : function(item) {
if (item.address != null) {
return ""+item.name+"";
}
return item.name;
}
},
{
//"data" : "address" //此写法错误,得用函数
"data" : "address"
},
{"data": "headMan"},
{
className : 'diyclass',
data : function(item) {
if (item.tel != null) {
return "";
}
return "click";
}
} ],
"columnDefs" : [ {
"defaultContent" : "",
"targets" : "_all"
} ]
});
});
function btntest(){
alert("电话获取中。。。");
}
ligerGrid
这个我感觉也很不错,主列从列都可以通过自定义的函数来控制样式和逻辑,非常灵活。有一个问题我没解决的是,怎么让表头左对齐?
function f_renderDetail(rowdata, index, value) {
if (rowdata.isArea) {
return value;
} else {
return ""+value+"";
}
}
function f_renderClick(rowdata, index, value) {
if (value != null) {
return "+rowdata.id+"\",\""+value+"\")'>"+value+"";
} else {
return value;
}
}
function clickTel(id,tel){
alert("这是"+id+"的电话:"+tel);
}
var manager;
$(function() {
// 不管是主列还是从列,都可以用 render 属性自定义样式和逻辑
manager = $("#maingrid").ligerGrid({
columns : [ {
display : '企业',
name : 'id',
width : '25%',
align : 'left',
render : f_renderDetail
}, {
display : '地址',
name : 'address',
width : '25%',
align : 'left'
}, {
display : '联系人',
name : 'headMan',
width : '25%',
align : 'left'
}, {
display : '电话',
name : 'tel',
width : '25%',
align : 'left',
render : f_renderClick //自定义样式、显示逻辑等
} ],
width : '80%',
// height : '97%',
// pageSizeOptions: [5, 10, 15, 20],
data : TreeData,
alternatingRow : false,
tree : {
columnName : 'id' //指定主列的属性
},
onDblClickRow : function (data, rowindex, rowobj) {
if(data.isArea){
alert("这是地区");
}else{
alert("这是企业");
}
}
// enabledEdit: true
});
manager.bind('beforeEdit', function(e) {
if (this.hasChildren(e.record))
return false;
else
return true;
});
});
最后,感谢以下博主
https://blog.csdn.net/duqian42707/article/details/52886220
https://blog.csdn.net/lhmyy521125/article/details/86528502