Bootstrap Tree View簡單而優(yōu)雅的樹結(jié)構(gòu)組件實(shí)例解析
A simple and elegant solution to displaying hierarchical tree structures (i.e. a Tree View) while leveraging the best that Twitter Bootstrap has to offer.
這是Bootstrap Tree View在git上的簡介。
注意simple、elegant,簡單而優(yōu)雅,我喜歡這兩個(gè)詞。
那么今天的實(shí)例是通過Bootstrap Tree View來制作一款省市級菜單的應(yīng)用。
一、效果圖

二、應(yīng)用
①、首先,項(xiàng)目需要引入bootstrap.css、jquery.js、bootstrap-treeview.js
<link type="text/css" rel="stylesheet" href="${ctx}/components/bootstrap/css/bootstrap.min.css" rel="external nofollow" />
<script type="text/javascript" src="${ctx}/components/jquery/jquery-1.10.1.min.js"></script>
<script type="text/javascript" src="${ctx}/components/treeview/js/bootstrap-treeview.js"></script>
②、接下來,頁面上需要放一個(gè)dom元素。
<div id="procitytree" style="height: 400px;overflow-y :scroll;"></div>
通過設(shè)置height和overflow-y,使treeview能夠在垂直方向上出現(xiàn)滾動條。
③、由于省市級數(shù)據(jù)一般都是固定不變的,那么頁面初次加載時(shí),我們把省市級數(shù)據(jù)先拿到。
Java端非常簡單:
@RequestMapping(value = "loadProcitysInfo")
public void loadProcitysInfo(HttpServletResponse response) {
logger.debug("獲取所有省市");
try {
List<Provincial> provincials = provincialService.getProvincials();
for (Provincial provincial : provincials) {
List<City> citys = cityService.getCitysByProvincialId(provincial.getId());
provincial.setCitys(citys);
}
renderJsonDone(response, provincials);
} catch (Exception e) {
logger.error(e.getMessage(), e);
logger.error(e.getMessage());
renderJsonError(response, Constants.SERVER_ERROR);
}
}
這段代碼需要優(yōu)化,通過mybatis其實(shí)可以一次就獲得省級和市級的集合。
獲取數(shù)據(jù)后,通過json寫入到response中。
protected void renderJsonDone(HttpServletResponse response, final Object value) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("statusCode", 200);
map.put("result", value);
String jsonText = JSON.toJSONString(map);
PrintWriter writer = null;
try {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(contentType);
writer = response.getWriter();
writer.write(jsonText);
writer.flush();
} catch (IOException e) {
throw new OrderException(e.getMessage());
} finally {
if (writer != null)
writer.close();
}
}
前端通過ajax對數(shù)據(jù)進(jìn)行組裝保存。
jQuery.ajax({
url : common.ctx + "/procity/loadProcitysInfo", // 請求的URL
dataType : 'json',
async : false,
timeout : 50000,
cache : false,
success : function(response) {
var json = YUNM.jsonEval(response);
if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok) {
var records = json[YUNM.keys.result];
if (!json)
return;
// 城市列表都存在
if (records != null && records.length > 0) {
// 遍歷子節(jié)點(diǎn)
$.each(records, function(index, value) {
var proNode = {};
// text是顯示的內(nèi)容
proNode["text"] = value.proname;
proNode["id"] = value.id;
proNode["procode"] = value.procode;
// 節(jié)點(diǎn)不可選中
proNode["selectable"] = false;
// 初始化市級節(jié)點(diǎn)
proNode["nodes"] = [];
$.each(value.citys, function(index, value) {
var cityNode = {};
cityNode["text"] = value.cname;
cityNode["id"] = value.id;
cityNode["proid"] = value.proid;
cityNode["code"] = value.code;
// 節(jié)點(diǎn)不可選中
cityNode["selectable"] = false;
proNode["nodes"].push(cityNode);
});
// 保存頁面端對象中
//YUNM._set.procityTreeData的數(shù)據(jù)結(jié)構(gòu)就是二維數(shù)組。
YUNM._set.procityTreeData.push(proNode);
});
}
}
}
});
④、拿到數(shù)據(jù)之后,就可以對treeview進(jìn)行初始化了。
這里,我們講一點(diǎn)更復(fù)雜的應(yīng)用,如下圖。

如果用戶已經(jīng)保存過一部分節(jié)點(diǎn),那么初次展示的時(shí)候就需要通過treeview展示出來了。
我們定一些規(guī)則:
節(jié)點(diǎn)全部選中時(shí)color為red,check框選中。
節(jié)點(diǎn)未全部選中時(shí)color為red,check框未選中。
節(jié)點(diǎn)一個(gè)也沒選中時(shí)color為默認(rèn),check框未選中。
為此,我們需要增加一點(diǎn)css。
/* 樹形省市 */
.treeview .list-group-item.node-checked {
color: red;
}
.treeview .list-group-item.node-selected {
color: red;
}
有了這個(gè)規(guī)則,我們在初次展開treeview的時(shí)候,就需要重新制定以下數(shù)據(jù)規(guī)則。
// 省市級數(shù)據(jù)
var procityTreeData = YUNM._set.procityTreeData;
// 用戶已經(jīng)選中的城市,比如河南洛陽。
var init_code = $this.next("input[name=area]").val();
// 如果用戶有選中項(xiàng),則對選中項(xiàng)進(jìn)行規(guī)則展示
if (init_code) {
// 初始化選中項(xiàng)目
$.each(procityTreeData, function(index, value) {
// 通過i和省級的節(jié)點(diǎn)length進(jìn)行對比,判斷是否全選、未全選、全未選三種狀態(tài)
var i = 0;
$.each(value.nodes, function(index1, value1) {
if (init_code.indexOf(value1.code) != -1) {
// 選中時(shí)先初始化state,再把state.checked設(shè)為true
value1["state"] = {};
value1["state"]["checked"] = true;
i++;
} else {
// 否則重置state,保證procityTreeData數(shù)據(jù)的不被更改
// 這個(gè)地方其實(shí)有待優(yōu)化,由于js我還不算精通,所以不知道怎么把數(shù)組復(fù)制到一個(gè)新數(shù)組里,保證原始屬于不被更改
value1["state"] = {};
}
});
value["state"] = {};
// 市級節(jié)點(diǎn)有選中,那么省級節(jié)點(diǎn)的狀態(tài)需要變化,根據(jù)上面制定的規(guī)則來
if (i > 0) {
// 市級全選,那么此時(shí)省級節(jié)點(diǎn)打鉤
if (value.nodes.length == i) {
value["state"]["checked"] = true;
}
// 根據(jù)selected來設(shè)定顏色
value["state"]["selected"] = true;
} else {
value["state"]["selected"] = false;
}
});
}
讓treeview和我們打個(gè)招呼吧!
$("#procitytree").treeview({
data : procityTreeData,// 賦值
highlightSelected : false,// 選中項(xiàng)不高亮,避免和上述制定的顏色變化規(guī)則沖突
multiSelect : false,// 不允許多選,因?yàn)槲覀円ㄟ^check框來控制
showCheckbox : true,// 展示checkbox
}).treeview('collapseAll', {// 節(jié)點(diǎn)展開
silent : true
});
⑤、節(jié)點(diǎn)onNodeChecked、onNodeUnchecked的應(yīng)用
不要⑤就夠了嗎?
不夠,我們還要控制節(jié)點(diǎn)選擇框的變化。
就像效果圖中那樣。

onNodeChecked : function(event, node) {
YUNM.debug("選中項(xiàng)目為:" + node);
// 省級節(jié)點(diǎn)被選中,那么市級節(jié)點(diǎn)都要選中
if (node.nodes != null) {
$.each(node.nodes, function(index, value) {
$this.treeview('checkNode', value.nodeId, {
silent : true
});
});
} else {
// 市級節(jié)點(diǎn)選中的時(shí)候,要根據(jù)情況判斷父節(jié)點(diǎn)是否要全部選中
// 父節(jié)點(diǎn)
var parentNode = $this.treeview('getParent', node.nodeId);
var isAllchecked = true; // 是否全部選中
// 當(dāng)前市級節(jié)點(diǎn)的所有兄弟節(jié)點(diǎn),也就是獲取省下面的所有市
var siblings = $this.treeview('getSiblings', node.nodeId);
for ( var i in siblings) {
// 有一個(gè)沒選中,則不是全選
if (!siblings[i].state.checked) {
isAllchecked = false;
break;
}
}
// 全選,則打鉤
if (isAllchecked) {
$this.treeview('checkNode', parentNode.nodeId, {
silent : true
});
} else {// 非全選,則變紅
$this.treeview('selectNode', parentNode.nodeId, {
silent : true
});
}
}
},
onNodeUnchecked : function(event, node) {
YUNM.debug("取消選中項(xiàng)目為:" + node);
// 選中的是省級節(jié)點(diǎn)
if (node.nodes != null) {
// 這里需要控制,判斷是否是因?yàn)槭屑壒?jié)點(diǎn)引起的父節(jié)點(diǎn)被取消選中
// 如果是,則只管取消父節(jié)點(diǎn)就行了
// 如果不是,則子節(jié)點(diǎn)需要被取消選中
if (silentByChild) {
$.each(node.nodes, function(index, value) {
$this.treeview('uncheckNode', value.nodeId, {
silent : true
});
});
}
} else {
// 市級節(jié)點(diǎn)被取消選中
var parentNode = $this.treeview('getParent', node.nodeId);
var isAllUnchecked = true; // 是否全部取消選中
// 市級節(jié)點(diǎn)有一個(gè)選中,那么就不是全部取消選中
var siblings = $this.treeview('getSiblings', node.nodeId);
for ( var i in siblings) {
if (siblings[i].state.checked) {
isAllUnchecked = false;
break;
}
}
// 全部取消選中,那么省級節(jié)點(diǎn)恢復(fù)到默認(rèn)狀態(tài)
if (isAllUnchecked) {
$this.treeview('unselectNode', parentNode.nodeId, {
silent : true,
});
$this.treeview('uncheckNode', parentNode.nodeId, {
silent : true,
});
} else {
silentByChild = false;
$this.treeview('selectNode', parentNode.nodeId, {
silent : true,
});
$this.treeview('uncheckNode', parentNode.nodeId, {
silent : true,
});
}
}
silentByChild = true;
},
到這里,treeview的應(yīng)用已經(jīng)算是非常全面了
以上所述是小編給大家介紹的Bootstrap Tree View簡單而優(yōu)雅的樹結(jié)構(gòu)組件實(shí)例解析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
TypeScript?Pinia實(shí)戰(zhàn)分享(Vuex和Pinia對比梳理總結(jié))
這篇文章主要介紹了TypeScript?Pinia實(shí)戰(zhàn)分享(Vuex和Pinia對比梳理總結(jié)),今天我們再來實(shí)戰(zhàn)下官方推薦的新的vue狀態(tài)管理工具Pini,感興趣的小伙伴可以參考一下2022-06-06
Typescript中bind的使用方法及注意事項(xiàng)
在TypeScript(以及JavaScript)中,bind()是一個(gè)用于改變函數(shù)上下文的方法,下面這篇文章主要給大家介紹了關(guān)于Typescript中bind的使用方法及注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下2024-08-08
兼容firefox的給每一個(gè)onClick再附加一個(gè)事件
如原來的onClick=="alert("a");",增加后變成onclick="alert("a");return false;"。 如果用腳本實(shí)現(xiàn)動態(tài)增加上去? 謝謝!2008-07-07
IE6-IE9中tbody的innerHTML不能賦值的解決方法
這篇文章主要介紹了IE6-IE9中tbody的innerHTML不能賦值的解決方法,很實(shí)用,需要的朋友可以參考下2014-09-09
echarts設(shè)置圖例顏色和地圖底色的方法實(shí)例
最近項(xiàng)目要使用echarts進(jìn)行數(shù)據(jù)可視化,所以下面這篇文章主要給大家介紹了關(guān)于echarts設(shè)置圖例顏色和地圖底色的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08
JavaScript中使用arguments獲得函數(shù)傳參個(gè)數(shù)實(shí)例
這篇文章主要介紹了JavaScript中使用arguments獲得函數(shù)傳參個(gè)數(shù)實(shí)例,本文用了多個(gè)例子來講解arguments的使用,需要的朋友可以參考下2014-08-08
javascript事件的傳播基礎(chǔ)實(shí)例講解(35)
這篇文章主要為大家詳細(xì)介紹了javascript事件的傳播基礎(chǔ)實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02

