首页 > 代码库 > easyUI同步树的详解

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来搞定父子级的关系,没有别的复杂操作了。

下面给出一张替换完图标的效果图:



在下一篇文章中,将会介绍异步树的使用方法~这种树的优点就是用到的时候再加载,节省了不必要的流量以及加载时间。




easyUI同步树的详解