文章目录
前言
最近在开发一些偏传统的应用,这些应用中涉及数据显示的时候,往往会用到较多的前端数据列表组件,这篇博客就简单总结一下这些常用的控件,虽然不同的前端组件会有很大差异,但是大致都差不多,使用方式也大同小异,只是组装数据的方式有些差异。
jqGrid
jqGrid是利用ajax,简单展示表格数据的一种解决方案,常用于后台管理系统中的数据表格展示,关于jqGrid中的各个参数可以参考如下几篇篇博客
jqGrid简单实用实例
1、准备一个HTML页面,其中包含jqGrid的div
<div id="main">
<table id="jqGrid"></table>
<div id="jqGridPager"></div>
</div>
这里其实指定
标签即可,后续的jqGridPager其实是用于处理分页的2、js初始化页面的代码
$(function () {
//初始化加载数据
$("#jqGrid").jqGrid({
url: baseURL + '/post/list',//这里是后端的请求接口url
datatype: "json",//绑定的数据类型,其实可以支持xml,具体参见中文文档
//数据字段一一绑定 <> 根据name
//label:显示的列标题
//name:列显示的后台字段数据名称
//index:传到服务器端用来排序用的列名
//width:列宽度
//align:对齐方式
//sortable:是否可以排序
//formatter:格式化处理数据的函数
colModel: [
{ label: 'Id', name: 'postId', index: "post_id", width: 45, key: true },
{ label: '岗位编码', name: 'postCode', index: "post_code", width: 75 },
{ label: '岗位名称', name: 'postName', index: "post_name", width: 75 },
{ label: '排序编号', name: 'orderNum', index: "order_num", width: 75 },
{ label: '备注', name: 'remark', width: 100 },
{ label: '状态', name: 'status', width: 60, formatter: function(value, options, row){
return value === 0 ?
'<span class="label label-danger">禁用</span>' :
'<span class="label label-success">正常</span>';
}},
{ label: '创建时间', name: 'createTime', index: "create_time", width: 85}
],
//是否需要形式总记录是,这里是需要显示
viewrecords: true,
//表格高度,可以是数字,也可以是像素,或者百分比
height: 425,
//默认每页显示的行数
rowNum: 10,
//分页序列
rowList : [5,10,20,40,60,80,100,120,200],
//是否在左边增加一列显示顺序号
rownumbers: true,
//如果rownumbers为true,这里就是设置显示顺序号列的宽度
rownumWidth: 25,
//根据页面中的父元素调整宽度,这里设置为true,允许根据父元素进行调整
autowidth:true,
//是否支持多行选中
multiselect: true,
//指定分页的元素id
pager: "#jqGridPager",
//读取服务器返回的json数据并解析(描述json数据格式的数组)
jsonReader : {
root: "data.page.list",
page: "data.page.currPage",
total: "data.page.totalPage",
records: "data.page.totalCount"
},
//设置jqGrid将要向服务端传递的参数名称
prmNames : {
page:"page",
rows:"limit",
order: "order"
},
//加载完成之后的函数,关闭底层的滚动条
gridComplete:function(){
//隐藏grid底部滚动条
$("#jqGrid").closest(".ui-jqgrid-bdiv").css({ "overflow-x" : "hidden" });
}
});
});
3、对应的后端接口返回的json数据
{
"code": 0,
"msg": "成功",
"data": {
"page": {
"totalCount": 10,
"pageSize": 10,
"totalPage": 1,
"currPage": 1,
"list": [
{
"postId": 1,
"postCode": "Rank1001",
"postName": "董事长",
"orderNum": 0,
"status": 1,
"createTime": "2019-07-22 23:16:28",
"updateTime": null,
"remark": "董事长"
},
{
"postId": 2,
"postCode": "Rank1002",
"postName": "总经理",
"orderNum": 1,
"status": 1,
"createTime": "2019-07-22 23:17:30",
"updateTime": null,
"remark": "总经理"
},
{
"postId": 3,
"postCode": "Rank1003",
"postName": "互联网技术总监",
"orderNum": 2,
"status": 1,
"createTime": "2019-07-23 09:25:38",
"updateTime": null,
"remark": "互联网技术总监"
},
{
"postId": 4,
"postCode": "Rank1004",
"postName": "财务总监",
"orderNum": 3,
"status": 1,
"createTime": "2019-07-23 09:25:55",
"updateTime": null,
"remark": "财务总监"
},
{
"postId": 5,
"postCode": "Rank1005",
"postName": "技术主管",
"orderNum": 4,
"status": 1,
"createTime": "2019-07-23 09:26:17",
"updateTime": null,
"remark": "技术主管"
},
{
"postId": 6,
"postCode": "Rank1006",
"postName": "产品经理",
"orderNum": 5,
"status": 1,
"createTime": "2019-07-23 09:27:02",
"updateTime": null,
"remark": "产品经理"
},
{
"postId": 7,
"postCode": "Rank1007",
"postName": "开发部经理",
"orderNum": 6,
"status": 1,
"createTime": "2019-07-23 09:27:14",
"updateTime": null,
"remark": "开发部经理"
},
{
"postId": 8,
"postCode": "Rank1008",
"postName": "运维主管",
"orderNum": 7,
"status": 1,
"createTime": "2019-07-23 09:27:23",
"updateTime": null,
"remark": "运维主管"
},
{
"postId": 9,
"postCode": "Rank1009",
"postName": "高级开发工程师",
"orderNum": 8,
"status": 1,
"createTime": "2019-07-23 09:27:35",
"updateTime": null,
"remark": "高级开发工程师"
},
{
"postId": 10,
"postCode": "R1019",
"postName": "HRBP",
"orderNum": 9,
"status": 1,
"createTime": "2019-07-23 09:27:52",
"updateTime": "2021-01-20 23:04:21",
"remark": "HRBP"
}
]
}
}
}
4、最终的展示效果如下
TreeGrid
jQuery TreeGrid是一个树形表格插件,可以直接用这个插件来完成树形数据的展示,例如:一个企业的部门信息通常是层级关系,需要进行层级展示。jQuery TreeGird的官网地址为——jQuery TreeGird官网。
但是纯原始的TreeGrid的使用并不是那么灵活,有些厉害的开发者对其进行了二次封装。为了在bootstrap中无缝的使用该插件,这里引用了经过二次封装的jQuery TreeGrid插件jquery.treegrid.extension.js,作者为:http://www.cnblogs.com/landeanfen/p/6776152.html。
TreeGrid数据展示实例
1、引入相关前端脚本依赖
<link rel="stylesheet" href="../statics/css/bootstrap-table.min.css">
<link rel="stylesheet" href="../statics/plugins/treegrid/jquery.treegrid.css">
<script src="../statics/libs/bootstrap-table.min.js"></script>
<script src="../statics/plugins/treegrid/jquery.treegrid.min.js"></script>
<script src="../statics/plugins/treegrid/jquery.treegrid.bootstrap3.js"></script>
<script src="../statics/plugins/treegrid/jquery.treegrid.extension.js"></script>
<script src="../statics/plugins/treegrid/tree.table.js"></script>
这里用到了相对路径,只需要注意对应的文件即可。
2、后端数据表准备
CREATE TABLE `sys_dept` (
`dept_id` bigint(20) NOT NULL AUTO_INCREMENT,
`parent_id` bigint(20) DEFAULT NULL COMMENT '上级部门ID,一级部门为0',
`name` varchar(50) DEFAULT NULL COMMENT '部门名称',
`order_num` int(11) DEFAULT NULL COMMENT '排序',
`del_flag` tinyint(4) DEFAULT '0' COMMENT '是否删除 -1:已删除 0:正常',
PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='部门管理'
关于如何获取后端数据的,这里不再展示
3、准备一个可以加载TreeGrid的HTML元素
<div>
<!--待展示数据的tree table-->
<table id="deptTable" data-mobile-responsive="true" data-click-to-select="true">
<thead>
<tr>
<th data-field="selectItem" data-checkbox="true"></th>
</tr>
</thead>
</table>
</div>
这里的deptTable就是显示层级数据的地方
4、相关初始化脚本
function initDeptTreeTable() {
$('#deptTable').bootstrapTreeTable({
id: 'deptId', // 选取记录返回的值
//code和parentCode才是用于标示父子层级的数据
code: 'deptId', // 用于设置父子关系
parentCode: 'parentId', // 用于设置父子关系
rootCodeValue: 0, //设置根节点code值----可指定根节点,默认为null,"",0,"0"
data: [], // 构造table的数据集合,如果是ajax请求则不必填写,会从后端去获取
type: "GET", // 请求数据的ajax类型
url: ctx + 'dept/list', // 请求数据的ajax的url
ajaxParams: {
deptName: $(".form").find("input[name='deptName']").val().trim()
}, // 请求数据的ajax的data属性
expandColumn: 2, // 在哪一列上面显示展开按钮
expandAll: true, // 是否全部展开
striped: true, // 是否各行渐变色
columns: [
{field: 'selectItem', radio: true},
{title: '部门ID', field: 'deptId', visible: false, align: 'center', valign: 'middle', width: '65px'},
{title: '部门名称', field: 'name', align: 'center', valign: 'middle', sortable: true, width: '180px'},
{title: '父级部门', field: 'parentName', align: 'center', valign: 'middle', sortable: true, width: '100px'},
{title: '排序编号', field: 'orderNum', align: 'center', valign: 'middle', sortable: true, width: '100px'}
], // 设置列
toolbar: null, //顶部工具条
height: 0,
expanderExpandedClass: 'fa fa-chevron-down', // 展开的按钮的图标
expanderCollapsedClass: 'fa fa-chevron-up' // 缩起的按钮的图标
});
}
//初始化的时候加载数据
$(function() {
initDeptTreeTable();
});
5、最终的显示结果如下:
实例参考博客:TreeGrid实例。
zTree
除了TreeGrid树形表格数据的展示,还有zTree,这种zTree就单纯的是某一个树形列表的展示,相比于TreeGrid,不会有太多的列,只会有单独的树形列的数据。
相关参考文档:zTree api文档。
相比上面的TreeGrid,zTree比较简单,这里直接上实例
zTree数据展示实例
1、准备zTree的HTML元素
<div id="deptLayer" style="display: none;padding:10px;">
<ul id="deptTree" class="ztree"></ul>
</div>
2、js中提供一个setting,用于设置zTree的初始化配置
var ztree;
//ztree配置
var setting = {
data: {
simpleData: {
//设置是否启用简单数据格式(zTree支持标准数据格式跟简单数据格式,上面例子中是标准数据格式)
enable: true,
//设置启用简单数据格式时id对应的属性名称
idKey: "deptId",
//设置启用简单数据格式时parentId对应的属性名称,ztree根据id及pid层级关系构建树结构
pIdKey: "parentId",
rootPId: -1
},
key: {
url:"nourl"
}
}
};
//需要展示的数据
var zNodes = [
{name : '节点1'},
{name : '节点2'}
];
//初始化zTree
ztree = $.fn.zTree.init($("#deptTree"), setting, zNodes);
3、可以ajax请求初始化zTree
$.get(baseURL + "/dept/select", function(r){
/**
* 设置ztree需要调用$.fn.zTree.init(element, setting, data);函数
这个函数需要三个参数,第一个参数是元素,第二个参数是setting,第三个参数是需要显示的数据
*/
ztree = $.fn.zTree.init($("#deptTree"), setting, r.data.deptList);
})
这里利用vue.js封装的发送ajax请求的方式初始化zTree
4、定义一个zTree的展开函数
指定一个输入框,并编写其点击事件的函数
<div class="col-sm-10">
<input type="text" class="form-control" style="cursor:pointer;" v-model="dept.parentName"
@click="deptTree" readonly="readonly" placeholder="父级部门"/>
</div>
点击输入框的绑定时间函数
//ztree打开事件 基于vue.js
deptTree: function(){
layer.open({
type: 1,
offset: '30px',
skin: 'layui-layer-molv',
title: "选择部门",
area: ['300px', '300px'],
shade: 0,
shadeClose: false,
content: jQuery("#deptLayer"),
btn: ['确定', '取消'],//这里是设置按钮
btn1: function (index) {//点击确定之后的函数操作
//TODO:点击确定之后的操作
layer.close(index);
}
});
},
5、展示结果:
常用的层级结构展示
在总结zTree控件数据展示的时候,涉及到了层级数据的展示,只是zTree这种控件比较强大,只需要指定数据的parent_id和id即可自动展示层级数据,但是有些层级数据的展示可不能全部依赖于这些控件。例如:在某些管理系统中,左侧菜单项的显示需要根据用户权限进行组装,不同的用户权限展示的权限列表不同,左侧菜单的层级填充也不一样,因此,很多时候也需要后端专门组装层级数据来返回给前端。这里就从后端开发的角度,简单总结一个实例。
1、定义一个菜单项的数据表以及对应的实体
//菜单管理
@Data
@TableName("sys_menu")
public class SysMenuEntity implements Serializable {
private static final long serialVersionUID = 1L;
//菜单ID
@TableId
private Long menuId;
//父菜单Id,*菜单为0
private Long parentId;
//父菜单名称
@TableField(exist=false)
private String parentName;
//菜单名称
//@NotBlank(message = "菜单名称不能为空!")
private String name;
//菜单链接url
private String url;
//授权编码(这个实例中可以不用关注这个属性)
private String perms;
//类型= 0:目录 1:菜单 2:按钮
private Integer type;
//菜单图标
private String icon;
//排序
private Integer orderNum;
@TableField(exist=false)
private List<SysMenuEntity> subMenuList;
}
定义了一个菜单实体类,不用关注全部属性,只需要关注最后一个属性——subMenuList。这个就是用于存储当前菜单项的子菜单列表数据的属性。
CREATE TABLE `sys_menu` (
`menu_id` bigint(20) NOT NULL AUTO_INCREMENT,
`parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
`name` varchar(50) DEFAULT NULL COMMENT '菜单名称',
`url` varchar(200) DEFAULT NULL COMMENT '菜单URL',
`perms` varchar(500) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',
`type` int(11) DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮',
`icon` varchar(50) DEFAULT NULL COMMENT '菜单图标',
`order_num` int(11) DEFAULT NULL COMMENT '排序',
PRIMARY KEY (`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8 COMMENT='菜单管理'
表结构中只需关注parent_id与menu_id
2、后端数据的组装
这里以超级管理员为例组装菜单数据,既然是超级管理员则其自然具有上帝视角,需要将所有菜单进行层级组装
2.1先找到一级菜单
/**
* 查询指定用户下的一级菜单数据。
* 根据父菜单id查询子菜单列表
* @param parentMenuId
* @return
*/
private List<SysMenuEntity> queryFirstLevelMenuList(Long parentMenuId){
//先查出所有的一级菜单
List<SysMenuEntity> allParentMenuList = baseMapper.queryListParentId(parentMenuId);
return userMenuList;
}
//上述queryListParentId方法,对应的SQL为
<select id="queryListParentId" resultType="com.learn.model.entity.SysMenuEntity">
select * from sys_menu where parent_id = #{parentId} order by order_num asc
</select>
2.2 再根据一级菜单进行递归
/**
* 获取所有菜单列表
* @param menuIdList
* @return
*/
public List<SysMenuEntity> getAllMenuList(List<Long> menuIdList){
//最终结果会存储在allMenuInfoList中。
List<SysMenuEntity> allMenuInfoList = queryFirstLevelMenuList(0L, menuIdList);
getMenuTrees(allMenuInfoList,menuIdList);
return allMenuInfoList;
}
/**
* 递归查询菜单数据
* @param menuList
* @param menuIdList
* @return
*/
private List<SysMenuEntity> getMenuTrees(List<SysMenuEntity> menuList){
//用来存储最终结果
List<SysMenuEntity> subMenuListResult = Lists.newLinkedList();
List<SysMenuEntity> tempMenuList;
//遍历父级菜单项,然后获取每一个父级菜单项下的一级菜单列表,然后递归调用下去。
for(SysMenuEntity menuEntity : menuList){
//获取父级菜单项的一级菜单列表
tempMenuList = queryFirstLevelMenuList(menuEntity.getMenuId());
if(CollectionUtils.isNotEmpty(tempMenuList)){
menuEntity.setSubMenuList(getMenuTrees(tempMenuList));
}
//如果没有下属菜单项了,则加入到最终存储结果的集合中
subMenuListResult.add(menuEntity);
}
return subMenuListResult;
}
最终返回结果为(贴出简单的示例)
{
"code": 0,
"msg": "成功",
"data": {
"menuList": [
{
"menuId": 61,
"parentId": 0,
"name": "测试目录(一级)",
"url": "/url/test",
"perms": "simple:test",
"type": 0,
"icon": "fa fa-adjust",
"orderNum": 0,
"open": null,
"subMenuList": [
{
"menuId": 62,
"parentId": 61,
"name": "测试目录(二级)",
"url": null,
"type": 0,
"icon": "fa fa-futbol-o",
"orderNum": 0,
"open": null,
"subMenuList": [
{
"menuId": 63,
"parentId": 62,
"name": "测试层级(三级)",
"url": null,
"type": 0,
"icon": "fa fa-sitemap",
"orderNum": 0,
"open": null,
"subMenuList": [
{
"menuId": 64,
"parentId": 63,
"name": "测试层级(四级)",
"url": "www.baidu.com",
"perms": "level:test",
"type": 1,
"icon": "fa fa-share",
"orderNum": 0,
"open": null,
"subMenuList": null
}
]
}
]
}
]
}
]
}
}
这样的数据一个菜单项下可以有多个子菜单。
总结
简单总结了各种数据展示的方式,最后的层级数据还算是比较通用的实例