0、寫在前面的話
最近看書都懈怠了,又正值新項目,雖說並不是忙得不可開交,好吧我老實交待,我就是偷懶了其實,博客也沒更。言歸正傳,對於前端的不熟悉現在確實是個讓我頭疼的事情,以至於一些功能要在網絡上漫天飛舞瘋狂嘗試才能做得出來,關鍵是特別費時間,確實得抽時間補補前端的基礎才是。這次要實現一個分類選擇,即圖片上傳之前,抓取所有的圖片分類,然后在上傳頁面做成下拉菜單欄進行選擇。效果如下圖,理論上要達到無限層級的下拉菜單:

1、bootstrap的按鈕下拉菜單欄
bootstrap是有直接可以使用的下拉菜單插件的:

如上圖,這個效果差不多就是我們想要的樣式了,可是該插件是不支持無限層級分支的,也就是說只有如上圖方式的主菜單“Java”和其子項。
2、無限層級的bootstrap按鈕下拉菜單欄
然而網友的力量是強大的,在bootstrap按鈕下拉菜單欄的基礎上,網友拓展實現了無限層級子菜單,參見:

可以看到這個效果絕對是非常棒了,that's what I want!
說動手就動手,通過作者給的demo可以看到:
<li class="offset-left dropdown">
<a href="#" class="dropdown-toggle">Dropdown...</a>
<ul class="dropdown-menu">
<li><a href="#">Secondary link</a></li>
<li><a href="#">Something else here</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Another link</a></li>
</ul>
</li>
10
1
<li class="offset-left dropdown">
2
<a href="#" class="dropdown-toggle">Dropdown...</a>
3
<ul class="dropdown-menu">
4
<li><a href="#">Secondary link</a></li>
5
<li><a href="#">Something else here</a></li>
6
<li><a href="#">Something else here</a></li>
7
<li class="divider"></li>
8
<li><a href="#">Another link</a></li>
9
</ul>
10
</li>
凡是有子菜單延伸的條目,由普通的<li><a></a></li>變成如上形式即可。
3、前后端交互,前端數據的展示
3.1 struts標簽的失敗和啟示
前端頁面使用的JSP,項目使用了Struts,所以前端是可以直接使用struts的標簽的。也就是說,列表實體類可以直接通過struts抓取其中的屬性List,再通過<s:iterator>,如<s:iterator value="category.childCategoryList">,然后通過if else判定,如果沒有子類,則設定其樣式形為
<li><a></a></li>,如果有子類,則設定其樣式形為<li class="offset-left dropdown"><a href="#" class="dropdown-toggle">MenuName</a><ul class="dropdown-menu">
<li><a></a></li>
</ul></li>
然而問題在於,每當子節點存在下一層子節點,我又必須增加一層if else判定,假如規定子分類最多4層,那么我的if判定也就寫4層好了,可是我們這個是理論上無限層級,假如用戶就是不斷建立分類細化,那怎么辦?顯然,這種方式是不合理的,而struts標簽頁沒有其他更好的方式來解決這種問題。
這種失敗在於數據的
局限性,
數據應該是后台處理好之后傳給前端,僅由前端來展示即可,而如上struts是將數據一股腦丟到前台,由前端來篩選組合處理,再進行展示,麻煩不言而喻。所以實際上應該將數據處理好,固化后再給前端解析使用。一旦數據結構固化,前端通過分析該數據,也就知道怎么做了。現在一般是使用Json,所以在我自己的這個例子中,我將后端的分類和子分類之間的關系,在后端轉換成json,傳遞給了前端,json結構如下:
[
{
"children": [
{
"children": [
{
"children": [],
"id": 10,
"text": "公司"
},
{
"children": [],
"id": 11,
"text": "兼職"
}
],
"id": 3,
"text": "工作"
},
{
"children": [],
"id": 4,
"text": "生活"
},
{
"children": [],
"id": 5,
"text": "個人"
}
],
"id": 2,
"text": "日常"
},
{
"children": [],
"id": 6,
"text": "高清大圖"
},
{
"children": [
{
"children": [],
"id": 8,
"text": "修改"
},
{
"children": [],
"id": 9,
"text": "測試回調"
}
],
"id": 7,
"text": "測試"
}
]
55
1
[
2
{
3
"children": [
4
{
5
"children": [
6
{
7
"children": [],
8
"id": 10,
9
"text": "公司"
10
},
11
{
12
"children": [],
13
"id": 11,
14
"text": "兼職"
15
}
16
],
17
"id": 3,
18
"text": "工作"
19
},
20
{
21
"children": [],
22
"id": 4,
23
"text": "生活"
24
},
25
{
26
"children": [],
27
"id": 5,
28
"text": "個人"
29
}
30
],
31
"id": 2,
32
"text": "日常"
33
},
34
{
35
"children": [],
36
"id": 6,
37
"text": "高清大圖"
38
},
39
{
40
"children": [
41
{
42
"children": [],
43
"id": 8,
44
"text": "修改"
45
},
46
{
47
"children": [],
48
"id": 9,
49
"text": "測試回調"
50
}
51
],
52
"id": 7,
53
"text": "測試"
54
}
55
]
3.2 遞歸生成html
有了數據,只需要通過數據解析,然后組成相關的html代碼即可。如上的json結構,可以看到只要有chidren屬性不為空,那么我們就可以在該部分生成子菜單形式的樣式,否則使用普通的樣式。這里就要用到遞歸了,因為是無限層級,否則使用if判定則又和struts一樣進入了死胡同。
菜單部分的html是通過數據和算法生成的,不是固定的,需要提醒一下。則正常時空空如也:
<td>分類<b>*</b><br/>
<div class="btn-group">
<button id="categoryButton" idx="0" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" style="width:215px">
請選擇圖片分類<span class="caret"></span>
</button>
<!--圖片分類的下拉菜單列表,通過js加載數據-->
<ul id="categories" class="dropdown-menu" role="menu">
<!--loading data in here-->
</ul>
</div>
</td>
11
1
<td>分類<b>*</b><br/>
2
<div class="btn-group">
3
<button id="categoryButton" idx="0" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" style="width:215px">
4
請選擇圖片分類<span class="caret"></span>
5
</button>
6
<!--圖片分類的下拉菜單列表,通過js加載數據-->
7
<ul id="categories" class="dropdown-menu" role="menu">
8
<!--loading data in here-->
9
</ul>
10
</div>
11
</td>
后端給前端傳遞的json數據,變量名這里為categories,即如下的var data,那么接下來通過一個遞歸方法:
var glb_str = "";
function createCategoryTree(data) {
var flag;
for (var i = 0; i < data.length; i++) {
var nodeText = data[i]['text'];
var nodeId = data[i]['id'];
var children = data[i]['children'];
//若有子分類,則遍歷子分類
if(children.length > 0) {
flag = true;
glb_str += "<li class='offset-right dropdown'><a class='category' " + "id=" + nodeId + " href='#'>" + nodeText + "...</a><ul class='dropdown-menu'>"
createCategoryTree(children);
} else {
//若沒有子分類
flag = false;
glb_str += "<li><a class='category' " + "id=" + nodeId + " href='#'>" + nodeText + "</a>";
}
if (flag) {
glb_str += "</ul></li>"
} else {
glb_str += "</li>";
}
}
return glb_str;
}
//以上為方法定義,該處為調用
var data = ${categories};
var result = createCategoryTree(data);
$("#categories").append(result);
x
1
var glb_str = "";
2
function createCategoryTree(data) {
3
var flag;
4
for (var i = 0; i < data.length; i++) {
5
var nodeText = data[i]['text'];
6
var nodeId = data[i]['id'];
7
var children = data[i]['children'];
8
//若有子分類,則遍歷子分類
9
if(children.length > 0) {
10
flag = true;
11
glb_str += "<li class='offset-right dropdown'><a class='category' " + "id=" + nodeId + " href='#'>" + nodeText + "...</a><ul class='dropdown-menu'>"
12
createCategoryTree(children);
13
} else {
14
//若沒有子分類
15
flag = false;
16
glb_str += "<li><a class='category' " + "id=" + nodeId + " href='#'>" + nodeText + "</a>";
17
}
18
19
if (flag) {
20
glb_str += "</ul></li>"
21
} else {
22
glb_str += "</li>";
23
}
24
}
25
return glb_str;
26
}
27
28
//以上為方法定義,該處為調用
29
var data = ${categories};
30
var result = createCategoryTree(data);
31
$("#categories").append(result);
加載完成的頁面,可以看到,頁面源碼中已經有列表的html代碼了:

4、參考鏈接
趕時間,寫得潦草了些,就這樣吧~