今天教大家使用jqGrid来实现异步加载的树形列表
先上效果图:
异步加载即不一次性的将所有的数据加载到页面上,只有当需要的时候点击三角按钮,才会将其子类加载到页面上显示,若其下无子类,则是圆圈标识。
下面是实现的步骤:
1.下载并引用必要的文件
这个就不详细讲了,网上有许多教程。
2.前端页面
一个table
一段JS
var jqGrid;
$(function() {
var width = $(".lz-card-body").width() - 20;
jqGrid = jQuery('#tree').jqGrid({
//
"url" : "/IssueConfig/findByPIdAndLevel",
"datatype" : "json",
"colModel" : [ {
"name" : "issConfigId",
"index" : "issConfigId",
"sorttype" : "int",
"key" : true,
"hidden" : true
}, {
"name" : "descCn",
"label" : "中文名称",
"sortable" : false,
/* formatter : function(cellvalue, options, rowObject) {
var viewUrl = "/sysMenu/toView/" + rowObject.id;
var html = "<a href='" + viewUrl;
html += "' target=_blank>";
html += cellvalue;
html += "</a>";
return html;
} */
}, {
"name" : "descEn",
"label" : "英文名称",
"sortable" : false
}, {
"name" : "issCode",
"label" : "序号",
"sortable" : false,
"align" : "center"
}, {
"name" : "issHelp",
"label" : "问题帮助",
"sortable" : false,
"align" : "center"
}, {
"name" : "sort",
"label" : "排序",
"sortable" : false,
"align" : "center",
/* formatter : function(cellvalue, options, rowObject) {
if(cellvalue){
return cellvalue.labelCn;
}
return '';
} */
}, {
"name" : "operation",
"label" : "操作",
"sortable" : false,
"width" : 100,
"align" : "center",
formatter : function(cellvalue, options, rowObject) {
var id = rowObject.issConfigId;
var addUrl = "/IssueConfig/toAdd/" + id;
var editUrl = "/IssueConfig/toEdit/" + id;
var html = "<a href='" + addUrl;
html += "' target=_blank title='add'>";
html += "<i class='fa fa-plus'></i></a> ";
html += "<a href='" + editUrl;
html += "' target=_blank title='edit'>";
html += "<i class='far fa-edit'></i></a>";
html += " <a href='#' title='delete' onclick=deleteMenu(";
html += id;
html += ")><i class='fa fa-trash'></i></a>";
return html;
}
}, {
"name" : "parentId",
"hidden" : true
}, {
"name" : "level",
"hidden" : true
}, {
"name" : "isLeaf",
"hidden" : true
}, {
"name" : "expanded",
"hidden" : true
}, {
"name" : "loaded",
"hidden" : true
} ],
"width" : width,
"hoverrows" : false,
"viewrecords" : false,
"gridview" : true,
"height" : "auto",
"sortname" : "issConfigId",
"sortable" : false,
"scrollrows" : true,
"tree_root_level" : 0,
"treeGrid" : true,
"ExpandColumn" : "descCn",
"treedatatype" : "json",
"treeGridModel" : "adjacency",
"loadonce" : false,
"rowNum" : 100,
"treeReader" : {
"parent_id_field" : "parentId",
"level_field" : "level",
"leaf_field" : "isLeaf",
"expanded_field" : "expanded",
"loaded" : "loaded",
"icon_field" : "icon1"
}
});
});
哎.....写的草稿没保存,不想在写一遍了
说一下重要的参数吧
tree_root_level" : 0,
"treeGrid" : true,
"ExpandColumn" : "descCn",
"treedatatype" : "json",
"treeGridModel" : "adjacency",
"loadonce" : false,
下面的是详细的api文档,不是太难
https://blog.csdn.net/yjlwl1213/article/details/41750703
3.后台代码
首先要知道,因为是弄清楚前台需要给后台什么参数,后台返给前台的数据结构是什么样子。
1.前台给后台
因为是异步加载,点击父节点才加载出其直接子节点,那么肯定要发回parent id,然后每一层 它的Level都要加1,所以要把父节点的level发回。
/**
* 根据parent_id和level查询菜单(异步加载)
*
* @param parentId
* @param level
* @return
*/
@RequestMapping(value = "/findByPIdAndLevel", method = RequestMethod.GET)
@ResponseBody
public List<IssueConfigVo> findByPIdAndLevel() {
//获得父节点和父节点的level
String nodeId = request.getParameter("nodeid");
String n_level = request.getParameter("n_level");
//null的话即为最开始加载的level=0的根节点
Long parentId = StringUtils.isEmpty(nodeId) ? null : Long.parseLong(nodeId);
Integer level = StringUtils.isEmpty(n_level) ? null : Integer.parseInt(n_level);
return issueConfigService.getMenusTree(parentId, level);
}
2.搞清楚要返回的数据结构,怎么样才能被前台识别形成树结构
//返回的类
public class IssueConfigVo extends IssueConfig {
private static final long serialVersionUID = 1L;
private Long id;
//父节点 id 其实这边不需要也可以,因为基础类里面就已经有parent 字段了,只需要在Js中设置一下
private Long parent;
private Integer level = 0;
private boolean isLeaf;
private boolean loaded = false;
private boolean expanded = true;
//数据
private IssueConfig father;
}
//实体类
@Entity
@Table(name = "NT_T_ISSUE_CONFIG")
public class IssueConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
// 主键
private Long issConfigId;
// 创建时间
private Date createDate;
// 创建人ID
private String createUserid;
// 创建人
private String createUsername;
// 中文描述
private String descCn;
// 英文描述
private String descEn;
// 问题序号
private String issCode;
// 问题帮助
private String issHelp;
// 修改时间
private Date modifyDate;
// 修改人员ID
private String modifyUserid;
// 上次节点
private Long parentId;
// 问题排序
private Integer sort;
// 状态
private String status;
}
3.递归获取List
/**
* 递归菜单
*
* @param param
* @return
*/
public List<IssueConfigVo> getMenusTree(Long pid, Integer level) {
List<IssueConfigVo> issueConfigVoList = new ArrayList<IssueConfigVo>();
//根据父节点id,找到其直接子节点
List<IssueConfigVo> issueConfigVo = IssueConfigVo
.setList(findByParentId(pid));
//设置level,因为我这边的业务需求,只有两层,如果需要多层,使用level +=1递增
if (level == null) {
level = 0;
} else {
level = 1;
}
if (issueConfigVo != null && !issueConfigVo.isEmpty()) {
for (IssueConfigVo menuVo : issueConfigVo) {
//设置子节点属性
menuVo.setLevel(level);
//这边是因为刚写的时候不了解,递归获取了子节点,其实是不需要的,
//因为实体类中有parent字段,我们只需要设置好parentId,并在前端
//js里面设置好,jqgrid就能将树拼接好
/*List<IssueConfigVo> children = getMenusTree(menuVo
.getIssConfigId());*/
if (children.isEmpty()) {
menuVo.setIsLeaf(true);
} else {
menuVo.setIsLeaf(false);
}
// menuVo.setChildren(children);
//设置parentId,一定要设置
menuVo.setParent(menuVo.getParentId());
issueConfigVoList.add(menuVo);
}
}
return issueConfigVoList;
}
//下面是递归获取子节点,有兴趣的人可以看一下,其实不需要
/**
* 递归菜单
*
* @param param
* @return
*/
public List<IssueConfigVo> getMenusTree(Long pid) {
List<IssueConfigVo> issueConfigVoList = new ArrayList<IssueConfigVo>();
List<IssueConfigVo> issueConfigVo = IssueConfigVo
.setList(findByParentId(pid));
if (issueConfigVo != null && !issueConfigVo.isEmpty()) {
for (IssueConfigVo menuVo : issueConfigVo) {
menuVo.setChildren(getMenusTree(menuVo.getIssConfigId()));
issueConfigVoList.add(menuVo);
}
}
return issueConfigVoList;
}
然后树就完成啦!最后,其实js里面也不需要那么麻烦,因为也是第一次写所以不熟悉,下面是精简班,主要功能不变,后台代码也不需要变动
jQuery(grid_selector).jqGrid({
treeGrid : true,
width : width,
treeGridModel : "adjacency",
ExpandColumn : "descCn",
ExpandColClick : false,
url : "/IssueConfig/findByPIdAndLevel",
datatype : "json",
colModel : [ {
name : "issConfigId",
index : "issConfigId",
key : true,
hidden : true,
formatter : function(cellvalue, options, rowObject) {
var rowId = rowObject.issConfigId;
var checkbox = '<input type="hidden" name=""';
checkbox += 'value="';
checkbox += rowId
checkbox += '"/>';
return checkbox;
}
}, {
label : nameFormat,
name : "descCn",
index : "descCn",
formatter : function(cellvalue, options, rowObject) {
index++;
var rowId = rowObject.issConfigId;
var descCn = rowObject.descCn;
var checkbox = '<input type="checkbox" id="chx';
checkbox += rowId;
checkbox += '" value="';
checkbox += descCn;
checkbox += '" onclick="clickCheckbox(';
checkbox += rowId;
checkbox += ', this);"';
checkbox += 'name=""';
checkbox += ' />';
checkbox += rowObject.descCn;
return checkbox;
}
}, {
label : "英文名称",
name : "descEn",
index : "descEn",
formatter : function(cellvalue, options, rowObject) {
var descEn = rowObject.descEn;
var checkbox = '<input type="hidden" ';
checkbox += ' name="" value="';
checkbox += descEn;
checkbox += '"/>';
checkbox += rowObject.descEn;
return checkbox;
}
} ,{
name : "issCode",
hidden : true,
formatter : function(cellvalue, options, rowObject) {
var issCode = rowObject.issCode;
var checkbox = '<input type="hidden" name=""';
checkbox += 'value="';
checkbox += issCode
checkbox += '"/>';
return checkbox;
}
}, {
name : "sort",
hidden : true,
formatter : function(cellvalue, options, rowObject) {
var sort = rowObject.sort;
var checkbox = '<input type="hidden" name=""';
checkbox += 'value="';
checkbox += sort
checkbox += '"/>';
return checkbox;
}
},{
name : "parentId",
hidden : true,
formatter : function(cellvalue, options, rowObject) {
var parentId = rowObject.parentId;
var checkbox = '<input type="hidden" name=""';
checkbox += 'value="';
checkbox += parentId
checkbox += '"/>';
return checkbox;
}
} ],
page : false,
rowNum: 100,
loadonce : false,
tree_root_level : 0,
gridview : true,
height : "auto"
});
有问题可以交流