常用数据的展示总结——jqGrid,TreeGrid,zTree简单使用小结以及层级数据展示小结

文章目录

前言

最近在开发一些偏传统的应用,这些应用中涉及数据显示的时候,往往会用到较多的前端数据列表组件,这篇博客就简单总结一下这些常用的控件,虽然不同的前端组件会有很大差异,但是大致都差不多,使用方式也大同小异,只是组装数据的方式有些差异。

jqGrid

jqGrid是利用ajax,简单展示表格数据的一种解决方案,常用于后台管理系统中的数据表格展示,关于jqGrid中的各个参数可以参考如下几篇篇博客

jqGrid各个参数说明

jqGrid-gitHub连接

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、最终的展示效果如下

常用数据的展示总结——jqGrid,TreeGrid,zTree简单使用小结以及层级数据展示小结

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、最终的显示结果如下:

常用数据的展示总结——jqGrid,TreeGrid,zTree简单使用小结以及层级数据展示小结

实例参考博客: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、展示结果:

常用数据的展示总结——jqGrid,TreeGrid,zTree简单使用小结以及层级数据展示小结

常用的层级结构展示

在总结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
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

这样的数据一个菜单项下可以有多个子菜单。

总结

简单总结了各种数据展示的方式,最后的层级数据还算是比较通用的实例

上一篇:js封装五级联动的区域zTree树插件


下一篇:乘风破浪,遇见未来元宇宙(Metaverse)之和Adobe一较高下的Quixel,发布第一款扫描树素材Megascans Trees,数字孪生整个自然界