easyUI同步樹的詳解
簡介樹控制元件
樹控制元件,很常用,比如它可以做有層級的選單。比如公司的部分劃分、省市區的選擇。。。
最大的好處就是有層級關係,看起來和選擇起來都比較清晰,就像一串雜亂無章的json你用bejson去格式化一樣的感覺。
所以,掌握樹控制元件,是很有必要的,為什麼?因為它很有用,用的恰當,也可以適當提升使用者體驗,
樹的兩種載入方式
tree的載入方式分為常規載入和非同步載入兩種,其中常規載入也就是一次性把整棵樹都加載出來,而非同步載入呢就是當展開父節點的時候才會去載入子節點。
一般肉眼上可以觀察到非同步載入的樹在點選父節點的時候會有一個load...的提示~其次呢你也可以抓包看~
好的~今天先來說說同步載入,這個在資料量較小的時候比較常用,還有一種情況,也不得不用同步載入,那就是在需要全選或者級聯選擇的時候。若使用非同步載入,那麼當你若未展開父節點而勾選了父節點的話,實際上只有父節點被選中(因為此時其下的子節點還未載入),也就造成了“選擇丟失”,所以這種情況需要使用同步載入。如果資料量很大,那麼需要給出適當的進度提示來提升使用者體驗。
Tree In EasyUI
看看tree在easyUI中的具體用法吧:
兩種方式來載入資料:一種是通過js的data,另外一種通過li標籤
<ul class="easyui-tree" data-options="url:'tree_data1.json',method:'get',animate:true"></ul>
<ul class="easyui-tree"> <li> <span>My Documents</span> <ul> <li data-options="state:'closed'"> <span>Photos</span> <ul> <li> <span>Friend</span> </li> <li> <span>Wife</span> </li> </ul> </li> <li> <span>Program Files</span> <ul> <li>Java</li> <li>Games</li> </ul> </li> <li>welcome.html</li> </ul> </li> </ul>
簡單吧,個人推薦使用js的方式來載入比較複雜的內容,因為組裝資料比較容易一些,弄個json丟過來就好了~
當然若使用Velocity等模板引擎,第二種方式似乎也不錯吧~好,言歸正傳,通過上面那一行程式碼相信你也明白了,tree的關鍵在於如何組織資料結構。
首先,我們要返回一個數組給前臺,結構類似:
[ { "id": 1, "text": "My Documents", "children": [ { "id": 11, "text": "Photos", "state": "closed", "children": [ { "id": 111, "text": "Friend" }, { "id": 112, "text": "Wife" } ] }, { "id": 14, "text": "about.html" }, { "id": 15, "text": "welcome.html" } ] } ]
這裡簡單解釋一下,這個陣列中的每一個json代表的是最高層的父級,如上只定義了一個最高父級——My Documents。並且這個最高父級下面包含了3個子級,分別是id為11的Photos、id為14的about、和id為15的welcome,相信應該看的出來吧。
id一般為該節點的識別符號,唯一
text則為該節點顯示的文字
state指定該節點的是展開的還是關閉的(對葉子節點無效)'open' or 'closed'.
其中Photos還有子級。。。而about和welcome則不包含子級,這種特殊的節點叫做葉子節點。相信大家也觀察到了,children這個屬性決定了該節點是否是葉子節點,若該屬性不存在或為空,那麼它就是葉子節點。
可以看看上述json對應的樹:
這裡也可以看到easyUI預設對於葉子節點的顯示是以“文件圖示”,而對於包含下級的節點用的是“資料夾圖示”,替換這些圖示也很簡單。
只需要在上述的屬性中,再定義一個iconCls就可以了~
像這樣的樹一般是單選樹,若我們想要支援多選的話,可以為每個圖示前加上一個多選框checkbox
<ul class="easyui-tree" data-options="checkbox:true,url:'tree_data1.json',method:'get',animate:true"></ul>
加上這個的話,那麼樹節點又多了一種屬性——checked,也就是指明是否被選中了。
所以總結一下,我們可以為tree node定義的屬性有這麼五種:id、text、state、iconCls、checked,別忘了,還有一個children,這個children也是一個treenode
那麼在後臺我們可以定義一個TreeNode的實體,方便我們組裝資料和整理邏輯。
具體應用
大概知道了tree的用法,那麼我們來考慮這麼一個場景,在酒店中,不同的服務員需要服務不同的客房,比如說小王負責4層和5層,小李負責6層和7層,當然也可能小王只負責三樓的部分房間。另外,酒店裡可能會有不同的樓,比如主樓和副樓,客房是歸在這些樓裡的。考慮到這裡是要選擇具體房間的,所以使用同步載入比較合理。
在這裡可以歸納出幾個層級關係:樓 號——》層號——》房間號(從高到低),並且樓號和層號都為父節點,而房間為葉子節點
並且我們這裡考慮加一個 “所有房間” 父節點,方便全選:
List<RoomNode> treeNodeList = new ArrayList<RoomNode>(1); // 第一層僅有一個head
RoomNode head = new RoomNode();
List<Node> children = new ArrayList<Node>();
head.setChildren(children);
head.setId("0");
head.setText("所有房間");
head.setIconCls("icon-tree-room-all");
treeNodeList.add(head);
List<Hall> buildingList = roomService.getAllHalls();
for (Hall _building : buildingList) {
List<GuestRoom> guestRoomList = roomService
.getAllGuestRoomsFloor(_building.getBg_code());
List<Node> floorList = new ArrayList<Node>(guestRoomList.size());
RoomNode building = new RoomNode();
building.setId(_building.getBg_code());
building.setText(_building.getBg_descript());
building.setState("closed");
building.setChildren(floorList);
building.setIconCls("icon-tree-room-building");
children.add(building);
for (GuestRoom _floor : guestRoomList) {
guestRoomList = roomService.getGuestRooms(_floor.getFloor(),
_building.getBg_code());
List<Node> roomList = new ArrayList<Node>(guestRoomList.size());
RoomNode floor = new RoomNode();
floor.setId(_floor.getFloor());
floor.setText(_floor.getFloor() + "樓");
floor.setState("closed");
floor.setChildren(roomList);
floor.setIconCls("icon-tree-room-floor");
floorList.add(floor);
for (GuestRoom _room : guestRoomList) {
RoomNode room = new RoomNode();
if (checkedRooms != null
&& checkedRooms.indexOf(_room.getRoomno().trim()) > -1) {
room.setChecked(true);
}
room.setId(_room.getRoomno().trim());
room.setText(_room.getRoomno() + "房");
room.setIconCls("icon-tree-room-room");
roomList.add(room);
}
}
}
同步載入的整個過程還是比較簡單,無非也就是通過setChildren來搞定父子級的關係,沒有別的複雜操作了。
下面給出一張替換完圖示的效果圖:
在下一篇文章中,將會介紹非同步樹的使用方法~這種樹的優點就是用到的時候再載入,節省了不必要的流量以及載入時間。