這是一個樹形菜單的展示。其功能及其強大,幾乎可以提供你對樹結構的各種要求。下面,對其簡述。
首先,感謝 Ivan Bozhanov利用JQuery對該組件的開發。同時還要感謝我的技術總監Mr. Lu和網友“漂流瓶”的幫助。
組件目前更新至 v0.9.8 版本,當然,版本還會繼續升級,作者試圖將它變得更加強大和完美,Ivan Bozhanov在博客中說:“I just thought it would be nice if I posted all my ideas for the upcoming 0.9.9 and see which ones you like, or do not like.”
使用JSTree,需要在文件頭寫類似如下內容的代碼,也就是說,它基於JQuery技術,自然需要jquery.js文件支持,同時還有css.js和tree_component.js這2個文件做支持以及tree_comopnent.css文件的渲染。
組件目前更新至 v0.9.8 版本,當然,版本還會繼續升級,作者試圖將它變得更加強大和完美,Ivan Bozhanov在博客中說:“I just thought it would be nice if I posted all my ideas for the upcoming 0.9.9 and see which ones you like, or do not like.”
使用JSTree,需要在文件頭寫類似如下內容的代碼,也就是說,它基於JQuery技術,自然需要jquery.js文件支持,同時還有css.js和tree_component.js這2個文件做支持以及tree_comopnent.css文件的渲染。
Js代碼:
<script src="<%=request.getContextPath() %>/js/jquery-0.9.6.js" type="text/javascript"></script>
<script src="<%=request.getContextPath() %>/js/css.js" type="text/javascript"></script>
<script type="text/javascript" src="<%=request.getContextPath() %>/js/tree_component.js"></script>
<link rel="stylesheet" href="<%=request.getContextPath() %>/css/tree_component.css" />
<script src="<%=request.getContextPath() %>/js/css.js" type="text/javascript"></script>
<script type="text/javascript" src="<%=request.getContextPath() %>/js/tree_component.js"></script>
<link rel="stylesheet" href="<%=request.getContextPath() %>/css/tree_component.css" />
這個樹,我們需要給它提供一個容器,如div。
容器內不需要給出內容,<div id="divForTree"></div>即可。內容會在JSTree被Init的時候來渲染。
容器內不需要給出內容,<div id="divForTree"></div>即可。內容會在JSTree被Init的時候來渲染。
PART A.
來看一個普通的樹:
Java代碼:
$(function () {
$.ajaxSetup({cache:false});//這個是為了樹的准確性做的一個緩存區清理的工作
$("#divForTree").tree({//從這里開始初始化JSTree
data : {
type : "json",//支持如xml等多種類型,這里是獲取JSON格式數據源
url : src,//每次獲得數據從這個鏈接
async : true,//動態加載數據
async_data : function (NODE) {//請求數據時帶的參數列表,可通過getParameter獲得。
return { parent_Id : $(NODE).attr("id") || 0}
}
},
lang:{
loading:"目錄加載中……" //在用戶等待數據渲染的時候給出的提示內容,默認為loading
},
ui:{//在這個option中設置context來控制JSTree的右鍵操作,如果在context的visible函數內始終返回false則表示在任何節點的右鍵都無效。
context:{visible : function (NODE, TREE_OBJ) {
return false;
}}
},
callback : {//響應函數,如節點被選中的onselect,還有onopen,onload,beforeopen等很多可定義內容。
onselect: function(node) {
//自定義操作
}
}
});
});
$.ajaxSetup({cache:false});//這個是為了樹的准確性做的一個緩存區清理的工作
$("#divForTree").tree({//從這里開始初始化JSTree
data : {
type : "json",//支持如xml等多種類型,這里是獲取JSON格式數據源
url : src,//每次獲得數據從這個鏈接
async : true,//動態加載數據
async_data : function (NODE) {//請求數據時帶的參數列表,可通過getParameter獲得。
return { parent_Id : $(NODE).attr("id") || 0}
}
},
lang:{
loading:"目錄加載中……" //在用戶等待數據渲染的時候給出的提示內容,默認為loading
},
ui:{//在這個option中設置context來控制JSTree的右鍵操作,如果在context的visible函數內始終返回false則表示在任何節點的右鍵都無效。
context:{visible : function (NODE, TREE_OBJ) {
return false;
}}
},
callback : {//響應函數,如節點被選中的onselect,還有onopen,onload,beforeopen等很多可定義內容。
onselect: function(node) {
//自定義操作
}
}
});
});
再看一下JSON的數據吧,可以在后台JAVA程序段獲得一個根據實際情況如當前打開節點的ID作為parent_id獲取它的子節點List。然后在一個JSP中迭代這個List(這里的迭代利用了Struts2的標簽):
Java代碼:
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
[
<s:iterator value="noteslist" >
{
attributes: { id : ${id} },
data: "${name}" ,state: "closed"
}
,
</s:iterator>
]
<%@ taglib prefix="s" uri="/struts-tags" %>
[
<s:iterator value="noteslist" >
{
attributes: { id : ${id} },
data: "${name}" ,state: "closed"
}
,
</s:iterator>
]
PART B.
現在看一個帶有右鍵操作的樹形菜單
Java代碼:
$(document).ready(function(){
$.ajaxSetup({cache:false});
$("#browser").tree({
data : {
type : "json",
url : src,
async : true,
async_data : function (NODE) {
return { parent_Id : $(NODE).attr("id") || 0}
}
},
lang:{
loading:"目錄加載中……"
},
rules:
{
draggable : "all" //這個設置可以使得節點進行拖動操作
},
ui:{
context : [ //自定義右鍵操作的可操作內容
{
id : "create",
label : "添加下級目錄", //右鍵彈出菜單的此項操作屏顯字樣
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); }, //允許節點被右擊時出現操作菜單
icon : "<%=request.getContextPath() %>/css/themes/default/create.png",//右鍵彈出菜單的此項操作圖標
action : function (NODE, TREE_OBJ) {
//進行此項操作,將有這個函數事件被響應
}
},
"separator"//這個是在兩個操作之間畫一條分隔線
,
{
id : "edit",
label : "編輯目錄信息",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/image/reg2.gif",
action : function (NODE, TREE_OBJ) {
openWindow('myurl','','',function(){treeRefresh($(NODE).attr("id"));});
}
},
"separator"
,
{
id : "privilege",
label : "設置目錄權限",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/css/themes/default/rename.png",
action : function (NODE, TREE_OBJ) {
openWindow('myurl','','',function(){treeRefresh($(NODE).attr("id"));});
}
},
"separator",
{
id : "delete",
label : "刪除",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/css/themes/default/remove.png",
action : function (NODE, TREE_OBJ) {
var tree=$.tree_reference("browser");
openWindow('myurl','','',function(){
//下邊的.parent()和.refresh()均為v0.9.8版本提供,如果你使用的是其他版本如v0.9.6等,這些將不被支持。
NODE=$(tree.parent(NODE));
if($(NODE).attr("id")==undefined){
tree.refresh();
}else{
TreeRefresh();
}
});
}
},
"separator",
{
id : "others",
label : "其他操作",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/css/images/cut.png",
action : function (NODE, TREE_OBJ) {
alert("暫無可提供操作。");
}
}
]
},
callback : {
onselect: function(node) {
//(a);
}
}
});
function treeRefresh(nodeid){
var rid=nodeid;
var tree=$.tree_reference("browser");
var par_node=tree.parent($("#"+rid));
tree.refresh(par_node);
}
});
$.ajaxSetup({cache:false});
$("#browser").tree({
data : {
type : "json",
url : src,
async : true,
async_data : function (NODE) {
return { parent_Id : $(NODE).attr("id") || 0}
}
},
lang:{
loading:"目錄加載中……"
},
rules:
{
draggable : "all" //這個設置可以使得節點進行拖動操作
},
ui:{
context : [ //自定義右鍵操作的可操作內容
{
id : "create",
label : "添加下級目錄", //右鍵彈出菜單的此項操作屏顯字樣
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); }, //允許節點被右擊時出現操作菜單
icon : "<%=request.getContextPath() %>/css/themes/default/create.png",//右鍵彈出菜單的此項操作圖標
action : function (NODE, TREE_OBJ) {
//進行此項操作,將有這個函數事件被響應
}
},
"separator"//這個是在兩個操作之間畫一條分隔線
,
{
id : "edit",
label : "編輯目錄信息",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/image/reg2.gif",
action : function (NODE, TREE_OBJ) {
openWindow('myurl','','',function(){treeRefresh($(NODE).attr("id"));});
}
},
"separator"
,
{
id : "privilege",
label : "設置目錄權限",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/css/themes/default/rename.png",
action : function (NODE, TREE_OBJ) {
openWindow('myurl','','',function(){treeRefresh($(NODE).attr("id"));});
}
},
"separator",
{
id : "delete",
label : "刪除",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/css/themes/default/remove.png",
action : function (NODE, TREE_OBJ) {
var tree=$.tree_reference("browser");
openWindow('myurl','','',function(){
//下邊的.parent()和.refresh()均為v0.9.8版本提供,如果你使用的是其他版本如v0.9.6等,這些將不被支持。
NODE=$(tree.parent(NODE));
if($(NODE).attr("id")==undefined){
tree.refresh();
}else{
TreeRefresh();
}
});
}
},
"separator",
{
id : "others",
label : "其他操作",
visible : function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return TREE_OBJ.check("creatable", NODE); },
icon : "<%=request.getContextPath() %>/css/images/cut.png",
action : function (NODE, TREE_OBJ) {
alert("暫無可提供操作。");
}
}
]
},
callback : {
onselect: function(node) {
//(a);
}
}
});
function treeRefresh(nodeid){
var rid=nodeid;
var tree=$.tree_reference("browser");
var par_node=tree.parent($("#"+rid));
tree.refresh(par_node);
}
});
PART C.
最后,再介紹一種帶有checkbox功能效果的JSTree
最后,再介紹一種帶有checkbox功能效果的JSTree
Java代碼:
$.ajaxSetup({cache:false});
$("#checktreeToshow").tree({
data : {
//內容同上,略過。
},
ui : {
//作者提供了checkbox效果的主題包,引入項目並指明包的位置
theme_path : "<%=request.getContextPath() %>/css/themes/",
//指出主題包的名字,如checkbox,或者是apple(蘋果操作平台下的效果主題)
theme_name : "checkbox",
//理論上指定了主題包的位置和主題包的名字就可以使用帶有checkbox功能的JSTree了,但我卻並沒有得到我想要的效果,所有的節點被點擊時無法被勾選。似乎主題包內的change.js沒有響應。因此我臨時做了個比較糟糕的實現,就是寫一個function checkChange(NODE, TREE_OBJ)函數,函數內容為checkbox主題包中change.js文件提供的onchange函數內容。自定義的checkChange函數即將你所操作的NODE節點的checkbox的勾選狀態取反。因為我的onchange沒有勾選效果,所以手工的添加了checkChange函數來實現。同理,我想要在節點的子節點加載進來后根據父節點是否被勾選來決定加載進來的子節點的勾選狀態,於是onopen函數也做了調整,不過這里的調整並不完善,有許多細節的瑕疵,如果你是JSTree的高手,歡迎交流經驗。
context:{visible : function (NODE, TREE_OBJ) {
return false;
}}
},
lang:{
loading:"目錄加載中……"
},
callback:
{
onchange : function (NODE, TREE_OBJ) {
checkChange(NODE, TREE_OBJ);
},
onopen:function(NODE, TREE_OBJ){
var $this = $(NODE).is("li") ? $(NODE) : $(NODE).parent();
var status=($this.children("a").attr("class").substring(0,7));
var tree=$.tree_reference("checktreeToshow");
if($(NODE).attr("where")=="0")
{
if(status=="checked")
{
checkChange(NODE, TREE_OBJ);
checkChange(NODE, TREE_OBJ);
}
}
else
{
if(status=="checked")
{
//NODE=$(tree.parent(NODE));
$this = $(NODE).is("li") ? $(NODE) : $(NODE).parent();
status=($this.children("a").attr("class")).substring(0,7);
if(status=="checked")
{
checkChange(NODE, TREE_OBJ);
checkChange(NODE, TREE_OBJ);
}
}
}
}
}
});
}
$("#checktreeToshow").tree({
data : {
//內容同上,略過。
},
ui : {
//作者提供了checkbox效果的主題包,引入項目並指明包的位置
theme_path : "<%=request.getContextPath() %>/css/themes/",
//指出主題包的名字,如checkbox,或者是apple(蘋果操作平台下的效果主題)
theme_name : "checkbox",
//理論上指定了主題包的位置和主題包的名字就可以使用帶有checkbox功能的JSTree了,但我卻並沒有得到我想要的效果,所有的節點被點擊時無法被勾選。似乎主題包內的change.js沒有響應。因此我臨時做了個比較糟糕的實現,就是寫一個function checkChange(NODE, TREE_OBJ)函數,函數內容為checkbox主題包中change.js文件提供的onchange函數內容。自定義的checkChange函數即將你所操作的NODE節點的checkbox的勾選狀態取反。因為我的onchange沒有勾選效果,所以手工的添加了checkChange函數來實現。同理,我想要在節點的子節點加載進來后根據父節點是否被勾選來決定加載進來的子節點的勾選狀態,於是onopen函數也做了調整,不過這里的調整並不完善,有許多細節的瑕疵,如果你是JSTree的高手,歡迎交流經驗。
context:{visible : function (NODE, TREE_OBJ) {
return false;
}}
},
lang:{
loading:"目錄加載中……"
},
callback:
{
onchange : function (NODE, TREE_OBJ) {
checkChange(NODE, TREE_OBJ);
},
onopen:function(NODE, TREE_OBJ){
var $this = $(NODE).is("li") ? $(NODE) : $(NODE).parent();
var status=($this.children("a").attr("class").substring(0,7));
var tree=$.tree_reference("checktreeToshow");
if($(NODE).attr("where")=="0")
{
if(status=="checked")
{
checkChange(NODE, TREE_OBJ);
checkChange(NODE, TREE_OBJ);
}
}
else
{
if(status=="checked")
{
//NODE=$(tree.parent(NODE));
$this = $(NODE).is("li") ? $(NODE) : $(NODE).parent();
status=($this.children("a").attr("class")).substring(0,7);
if(status=="checked")
{
checkChange(NODE, TREE_OBJ);
checkChange(NODE, TREE_OBJ);
}
}
}
}
}
});
}
下面是我自定義的checkChange函數,函數體為主題中change.js文件提供的函數內容:
Java代碼:
function checkChange(NODE, TREE_OBJ)
{
var $this = $(NODE).is("li") ? $(NODE) : $(NODE).parent();
if($this.children("a.unchecked").size() == 0) {
TREE_OBJ.container.find("a").addClass("unchecked");
}
$this.children("a").removeClass("clicked");
if($this.children("a").hasClass("checked")) {
$this.find("li").andSelf().children("a").removeClass("checked").removeClass("undetermined").addClass("unchecked");
var state = 0;
}
else {
$this.find("li").andSelf().children("a").removeClass("unchecked").removeClass("undetermined").addClass("checked");
var state = 1;
}
$this.parents("li").each(function () {
if(state == 1) {
if($(this).find("a.unchecked, a.undetermined").size() - 1 > 0) {
$(this).parents("li").andSelf().children("a").removeClass("unchecked").removeClass("checked").addClass("undetermined");
return false;
}
else $(this).children("a").removeClass("unchecked").removeClass("undetermined").addClass("checked");
}
else {
if($(this).find("a.checked, a.undetermined").size() - 1 > 0) {
$(this).parents("li").andSelf().children("a").removeClass("unchecked").removeClass("checked").addClass("undetermined");
return false;
}
else $(this).children("a").removeClass("checked").removeClass("undetermined").addClass("unchecked");
}
});
}
{
var $this = $(NODE).is("li") ? $(NODE) : $(NODE).parent();
if($this.children("a.unchecked").size() == 0) {
TREE_OBJ.container.find("a").addClass("unchecked");
}
$this.children("a").removeClass("clicked");
if($this.children("a").hasClass("checked")) {
$this.find("li").andSelf().children("a").removeClass("checked").removeClass("undetermined").addClass("unchecked");
var state = 0;
}
else {
$this.find("li").andSelf().children("a").removeClass("unchecked").removeClass("undetermined").addClass("checked");
var state = 1;
}
$this.parents("li").each(function () {
if(state == 1) {
if($(this).find("a.unchecked, a.undetermined").size() - 1 > 0) {
$(this).parents("li").andSelf().children("a").removeClass("unchecked").removeClass("checked").addClass("undetermined");
return false;
}
else $(this).children("a").removeClass("unchecked").removeClass("undetermined").addClass("checked");
}
else {
if($(this).find("a.checked, a.undetermined").size() - 1 > 0) {
$(this).parents("li").andSelf().children("a").removeClass("unchecked").removeClass("checked").addClass("undetermined");
return false;
}
else $(this).children("a").removeClass("checked").removeClass("undetermined").addClass("unchecked");
}
});
}
以上為個人的一點小總結,可以給我作為備忘以便以后再使用。如果你也在使用JQuery的JSTree,希望能對你有些許幫助,同時它更多的內容我也在不斷嘗試中。
最后再說一下,JSTree下載后下載包中會自帶JQuery的jquery.js文件,使用這個肯定沒問題,但如果你的項目已經存在了jquery.js文件,有可能會出現
$("#" + this.container.attr("id") + " li").live is not a function tree_component.js (第 1028 行) 【注:該異常捕獲於FF瀏覽器,使用的JSTree為v0.9.6】,因為JSTree對JQuery的版本還是有依賴性的,作者對此異常的解釋為:“It is the jQuery version that is used. You need to use the supplied jQuery (or the latest from
http://jquery.com) . Version 1.2.6 does not support live events (they are introduced in 1.3).”