[jstree] jstree 學習筆記
jstree 是一個好用的樹元件。基於 javascrpt 打造,適用於不同的瀏覽器。它被打包成 jquery 的插件,同時,他宣稱絕對免費。
樹元件在現在的視窗元件非常重要,你在檔案總管的左側一定會看到,沒有了它,要在各目錄間移動,將會非常不方便。
接下來,我把我學習如何使用這個元件的過程整理一下,就像是官方文件閱讀指南一般,而這過程,剛好就是由淺而深,由易而難的學習過程,希望可以幫助到有需要的人走一條比較平緩的學習之路。
在頁面引入
官網在文件的 core 頁有說明 http://www.jstree.com/documentation/core
其實,第一件事是下載 jstree 的檔案。在首頁http://www.jstree.com/的左上角有個綠色的下載按鈕,那裡打包的才符合文件所說。我曾經因為那個下載按鈕失效而去 github 下載,照文件來做發現是不能用的。原因我沒找出來,我想因為我不是 javascript 專家,所以沒辦法找出原因。
回到正題,在頁面引入,要先把檔案下載回來,現在是 jstree-v.pre1.0.zip。內容如下:
裡面的 jquery.jstree.js 就是了。
因為 jstree 寫成 jquery 的 plugin,所以第一個要引入的是 jquery。
<script type="text/javascript" src="_lib/jquery.js"></script>
若 jquery 你放在別的位置,就不用照抄。
接下來就是引入 jstree。有兩個版本,功能都一樣,只是一個 size 比較大,一個比較小。
<script type="text/javascript" src="jquery.jstree.js"></script>
其實任何位置都可以,只要你清楚改位置之後的影響。文件上有提到,檔名儘量不要改,因為像是 themes 插件的檔案路徑偵測會用到。如果非改不可,多數的插件有選項可以手動設定路徑。(也就是自動路徑偵測失效,只能自己手動設定各插件會用到路徑。)
很貼心的是,jstree 會需要的插件,若是有缺少引入,它會主動告知。
準備資料
在使用 jstree 之前要準備資料,才能讓 jstree 顯示。我一開始一頭霧水,不知道在哪裡有說明如何準備資料給jstree。於是在它的 demo 網頁挖,用 chrome 的開發者工具看。後來發現其實有說明,只是在不同的地方。
jstree 可以用的資料格式有三種。HTML、JSON、XML。要讀入資料時,要開啟不同的 jstree 插件。
HTML
官網文件在http://www.jstree.com/documentation/html_data
要使用 HTML 當資料來源,需要開啟 HTML_DATA 插件。
資料的格式如下:
<li>
<a href="some_value_here">Node title</a>
<!-- UL node only needed for children - omit if there are no children -->
<ul>
<!-- Children LI nodes here -->
</ul>
</li>
jstree 會讀到資料後改變資料的結構。
<!-- one of the three classes will be applied depending on node structure -->
<li class="[ jstree-open | jstree-closed | jstree-leaf ]">
<!-- an INS element is inserted -->
<ins class="jstree-icon"> </ins>
<a href="some_value_here">
<!-- another INS element is inserted -->
<ins class="jstree-icon"> </ins>
Node title
</a>
</li>
因此,底下是我做出來最簡單的範例,資料已經在網頁準備好的。
<html>
<script src="js/jquery-1.7.2.js"></script>
<script src="js/jquery.jstree.js"></script><script>
$(document).ready(function () {
$("#demo1").jstree({
"plugins" : [ "themes", "html_data" ]});
});
</script>
<body>
<div id="demo1" class="demo">
<ul>
<li>
<a href="#">Root node 1</a>
<ul>
<li>
<a href="#">Child node 1</a>
</li>
<li>
<a href="#">Child node 2</a>
</li>
</ul>
</li>
<li>
<a href="#">Root node 2</a>
</li>
</ul>
</div>
</body>
</html>
執行結果:(如果看起來少個目錄圖示,我就是這樣,因為拿別人的網頁來改的。那可能拿到舊的 css,一定要在下載下來的 zip 拿整包的 icon 及 css。)
這樣就已經是可以點擊張開及收合的功能。
若是要改用設定的方式呢?以下是範例。
<html>
<script src="js/jquery-1.7.2.js"></script>
<script src="js/jquery.jstree.js"></script><script>
$(document).ready(function () {
$("#demo1").jstree({
"core" : { "initially_open" : [ "root" ] },
"plugins" : [ "themes", "html_data" ],
"html_data" : {
"data" : '<li id="root"><a href="#">Root node 1</a><ul><li><a href="#">Child node 1</a></li><li><a href="#">Child node 2</a></li></ul></li><li><a href="#">Root node 2</a></li>'
}
});
});
</script>
<body>
<div id="demo1" class="demo">
</div>
</body>
</html>
這範例是參考官方文件的,裡面順手交了一招核心功能的設定,預定打開的節點。
"core" : { "initially_open" : [ "root" ] }
該設定要傳入的是一個字串陣列,其內容是節點(<li>)的 id 值。要小心 id 設定時不能重覆,在一個網頁內要唯一。
使用 ajax 方式,我想等三種方式的基本都講完再說。因為他們有共通的奇妙之處。
json
官方文件在這http://www.jstree.com/documentation/json_data
要使用 json 當資料來源,要把 json_data 插件打開。基本的 json 資料結構要長成以下的樣子。
{
"data" : "node_title",
// omit `attr` if not needed; the `attr` object gets passed to the jQuery `attr` function
"attr" : { "id" : "node_identificator", "some-other-attribute" : "attribute_value" },
// `state` and `children` are only used for NON-leaf nodes
"state" : "closed", // or "open", defaults to "closed"
"children" : [ /* an array of child nodes objects */ ]
}
其中,data 是節點名稱,也就是 ui 上看到的名稱。attr 是給 jquery 的 attr 用的,若是有些東西要操作,id 很重要,那麼就必須在這裡設定,這裡的屬性會設定成 <li> 的屬性。state 是預設打開或關閉此結點。children 就是放子節點的位置。
<html>
<script src="js/jquery-1.7.2.js"></script>
<script src="js/jquery.jstree.js"></script>
<script>
$(document).ready(function () {
$("#demo1").jstree({
"core" : { "initially_open" : [ "root" ] },
"plugins" : [ "themes", "json_data" ],
"json_data" : {
"data" : [
{
"data":"Root node 1",
"attr":{"id":"node_1"},
"state":"open",
"children":[
{
"data":"Child node 1",
"attr":{"id":"node_2"},
"state":"open"
},
{
"data":{
"title":"Child node 2",
"attr":{"href":"node2.html"}
},
"attr":{"id":"node_3"},
"state":"open"
}
]
},
{
"data":"Root node 1",
"attr":{"id":"node_4"},
"state":"closed",
"children":[]
}
]
}
});
});
</script>
<body>
<div id="demo1" class="demo">
</div>
</body>
</html>
執行起來就跟之前的畫面一樣。
還記得,經過 jstree 處理過的節點的 html 樣子嗎?在 <li> 裡面有 <a>,若是要設定 <a> 的屬性,例如 href,那麼就要如同上面的 Child node 2 的設定方式。注意看 Child node 1 與 Child node 2 的不同,就在於 data 的值,一個是字串,一個是物件。物件裡面的 title 屬性就是節點的名稱,物件裡面的 attr 屬性就是 <a> 的 attr,物件裡面的 icon 屬性,若有 / 則會變成背景,不然就當 class 的值。
{
"data":"Child node 1",
"attr":{"id":"node_2"},
"state":"open"
},
{
"data":{
"title":"Child node 2",
"attr":{"href":"node2.html"}
},
"attr":{"id":"node_3"},
"state":"open"
}
XML
與其他兩種方式相比,使用 XML,有兩種表示方式,一種是階層式。一種是平坦式,怎麼說呢?
它的結構如下:
<root>
<item id="root_1" parent_id="0" state="closed">
<content>
<name><![CDATA[Node 1]]></name>
</content>
</item>
<item id="node_2" parent_id="root_1">
<content>
<name><![CDATA[Node 2]]></name>
</content>
</item>
</root>
每個節點在 xml 裡是放在同一層,要組合成樹,就靠 parent_id 來連。這種方法對於資料是存放在資料表裡的人來說,是一大福音,代表自己可以少寫一段組合成樹的程式。
這裡的規則也很簡單,所有在 item 的屬性,都會轉到 <li> 的屬性。所有在 name 的屬性,都會轉到 <a> 的屬性。
為了避免使用到 xml 的保留字元,name 裡面的文字節點內容要用 CDATA 夾住。
厲害的 ajax 屬性
在三個資料來源的設定,ajax 的設定非常靈活。
在 http://www.jstree.com/documentation/html_data 裡面有個例子,「Using the ajax config option」。你如果去點開 Node 1,它底下長出 Node 1, Node2,再點開底下的 Node 1,又再長出兩個,越點越多…。
ajax 裡面的 data 屬性若是設定成一個 function,可以在裡面獲得被點擊的節點,也就可以拿到被點擊點的 id。在這 function 回傳的資料,會被當成 ajax 的 data 項目回傳給 server。
我寫了個範例如下:
<html>
<script src="js/jquery-1.7.2.js"></script>
<script src="js/jquery.jstree.js"></script>
<script>
$(document).ready(function () {
$("#demo1").jstree({
"plugins" : [ "themes", "json_data" ],
"json_data" : {
"ajax":{
"url":"ajax.html",
"data":function(n){
return {id : n.attr ? n.attr("id") : 0 };
}
}
}
});
});
</script>
<body>
<div id="demo1" class="demo">
</div>
</body>
</html>
要準備一個 ajax.html 檔,其實裡面內容是 json 格式(反正 iis 不在乎)
[
{
"data":"Root node 1",
"attr":{"id":"node_1"},
"state":"open",
"children":[
{
"data":"Child node 1",
"attr":{"id":"node_2"},
"state":"closed"
},
{
"data":{
"title":"Child node 2",
"attr":{"href":"node2.html"}
},
"attr":{"id":"node_3"},
"state":"closed"
}
]
},
{
"data":"Root node 1",
"attr":{"id":"node_4"},
"state":"closed",
"children":[]
}
]
依靠範例中的寫法,每次點開節點時,便會有 request 送到 server。data function 回傳的資料都當成 querystring 送出。
同時,ajax 裡面的 url 若是設定成 function,那它也可以在裡面得到被點擊的節點,同時,this 在那個 function 裡代表的是 jstree 的實例。在那裡面回傳的,會被當做是 url,於是就可動態產生 url,在採用 REST 開發的網站可以用 /get_children/node_2 之類的拿到資料。
以下是我的範例:
<html>
<script src="js/jquery-1.7.2.js"></script>
<script src="js/jquery.jstree.js"></script>
<script>
$(document).ready(function () {
$("#demo1").jstree({
"plugins" : [ "themes", "json_data" ],
"json_data" : {
"ajax":{
"url":function(n){
var _id = n.attr ? n.attr("id"):0;
return _id + "/ajax.html"
}
}
}
});
});
</script>
<body>
<div id="demo1" class="demo">
</div>
</body>
</html>
結論
在這裡先快速帶到可以看得見的例子,把引入,資料準備的各種方式寫清楚,就不會一直 try and error 都看不到東西 (就是說我自己)。同時,了解 ajax 屬性的用法,可以善用其特性提高效能及使用者經驗。