当选择的节点具有单一性质时,树形结构菜单在项目中会经常使用到。这里,笔者就以实例介绍一下树形菜单功能的实现。效果如下图所示:
实现树形菜单主要的思路:前端向服务器发送请求,获取服务器响应的数据,解析数据,显示成树形菜单,最关键的两点就是:第一,前端需要什么样的数据?树形菜单需要的数据无非就是一个对象里面包含一个该对象的集合,具体看前端选择什么样的框架,不使用框架也可以,使用纯页面和原生js也可以实现,只是样式,数据解析都得自己写,这里,笔者选用layui前端框架,需要的数据是一个分支对象的集合。
第二,后台怎样包装数据?后台包装树形菜单数据的方法有两种,第一种是使用for循环,不断地向集合对象中添加数据,直到最后一个叶子节点;第二种是使用递归的方法,遍历所有数据,不断地调用一个包装数据的方法,直到最后一个数据。
前端代码:
<body>
<h2 style="margin-left: 50px;margin-top: 50px">省市区树形结构菜单</h2>
<ul id="demo" style="margin-left: 50px;margin-top: 10px"></ul>
<script src="../../../layuiadmin/layui/layui.js" type="text/javascript" charset="utf-8"></script>
<script src="../../content/js/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../../layuiadmin/lib/formTools.js" type="text/javascript"></script>
<script type="text/javascript">
layui.use(['tree', 'layer'], function () {
var layer = layui.layer;
var selectedArea=null;
layui.tree({
elem: '#demo',
nodes: formTool.ajax(null, "test/nodes").data,
click: function (node) {
layer.msg(node.name+"----"+node.prefecture.prefectureId, {icon: 1});
selectedArea=node.prefecture.prefectureId;
}
});
$(".layui-tree li a").click(function() {
if($(".layui-tree li a").hasClass("selectedColor")) $(".layui-tree li a").removeClass("selectedColor");
$(this).addClass("selectedColor");
});
});
</script>
</body>
后台实体类代码:
public class Nodes {
private String name;
private Boolean spread;
private String href;
private List<Nodes> children;
private Prefecture prefecture;
public Prefecture getPrefecture() {
return prefecture;
}
public void setPrefecture(Prefecture prefecture) {
this.prefecture = prefecture;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getSpread() {
return spread;
}
public void setSpread(Boolean spread) {
this.spread = spread;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public List<Nodes> getChildren() {
return children;
}
public void setChildren(List<Nodes> children) {
this.children = children;
}
}
后台Controller代码:
第一种方法:分别查询,循环包装数据
/**
* 分级查询包装成List<Nodes>返回给前台,有几级就查询几次
*/
@RequestMapping(value = "nodes",method = RequestMethod.POST)
public NeTableResponse<List<Nodes>> nodes(){
NeTableResponse<List<Nodes>> json=new NeTableResponse<List<Nodes>>();
//返回的Nodes对象的集合
List<Nodes> nodesList=new ArrayList<>();
List<Prefecture> prefectureProvince = nodesService.queryProvince();
//遍历省
for (Prefecture province:prefectureProvince) {
Nodes nodesProvince=new Nodes();
nodesProvince.setName(province.getPrefecture());
nodesProvince.setPrefecture(province);
List<Prefecture> prefectureCity = nodesService.queryChildren(province.getPrefectureId());
List<Nodes> nodesCityList=new ArrayList<>();
//遍历市,并添加到所属的省
for (Prefecture city:prefectureCity) {
Nodes nodesCity=new Nodes();
nodesCity.setName(city.getPrefecture());
nodesCity.setPrefecture(city);
List<Prefecture> prefectureCountry= nodesService.queryChildren(city.getPrefectureId());
List<Nodes> nodesCountryList=new ArrayList<>();
//遍历区县,并添加到所属的市
for (Prefecture country:prefectureCountry) {
Nodes nodesCountry=new Nodes();
nodesCountry.setName(country.getPrefecture());
nodesCountry.setPrefecture(country);
nodesCountryList.add(nodesCountry);
}
nodesCity.setChildren(nodesCountryList);
nodesCityList.add(nodesCity);
}
nodesProvince.setChildren(nodesCityList);
nodesList.add(nodesProvince);
}
return json.setData(nodesList);
}
第二种方法:使用递归遍历数据包装数据
/**
* 先查询出所有,然后使用递归包装数据,只查询一次
*/
@RequestMapping(value = "getNodes",method = RequestMethod.POST)
public NeTableResponse<List<Nodes>> getNodes(){
NeTableResponse<List<Nodes>> json=new NeTableResponse<List<Nodes>>();
//查询所有的地区
List<Prefecture> prefectureAll = nodesService.queryAll();
List<Nodes> nodesList = this.packNodes(prefectureAll, 1);
return json.setData(nodesList);
}
/**
* 对查询的所有结果递归遍历
*/
private List<Nodes> packNodes(List<Prefecture> prefectureAll,Integer code){
List<Nodes> nodesList=new ArrayList<>();
for (Prefecture prefecture:prefectureAll) {
if (prefecture.getPrefectureLevel()==code){
Nodes nodes=new Nodes();
nodes.setName(prefecture.getPrefecture());
nodes.setPrefecture(prefecture);
nodes.setChildren(this.packNodes(prefectureAll,Integer.parseInt(prefecture.getPrefectureId())));
nodesList.add(nodes);
}else if(String.valueOf(code).equals(prefecture.getSupPrefectureId())){
Nodes nodes=new Nodes();
nodes.setName(prefecture.getPrefecture());
nodes.setPrefecture(prefecture);
if(prefecture.getLastStage()!=1) nodes.setChildren(this.packNodes(prefectureAll,Integer.parseInt(prefecture.getPrefectureId())));
nodesList.add(nodes);
}
}
return nodesList;
}
这里发现了IDEA开发工具的另一个智能的地方,如果使用了递归,左侧会有递归recursion的标识,如下图: