當選擇的節點具有單一性質時,樹形結構菜單在項目中會經常使用到。這裡,筆者就以執行個體介紹一下樹形菜單功能的實作。效果如下圖所示:

實作樹形菜單主要的思路:前端向伺服器發送請求,擷取伺服器響應的資料,解析資料,顯示成樹形菜單,最關鍵的兩點就是:第一,前端需要什麼樣的資料?樹形菜單需要的資料無非就是一個對象裡面包含一個該對象的集合,具體看前端選擇什麼樣的架構,不使用架構也可以,使用純頁面和原生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的辨別,如下圖: