ztree插件:优雅实现多层级树形菜单
在Web开发中,树形菜单是比较常见的UI控件之一,特别是在针对复杂数据结构进行展示的时候,比如公司组织结构图、目录树等。虽然通过手写代码也可以实现树形菜单的功能,但是对于非常复杂的层级和数据结构,手写往往会非常麻烦和困难,可维护性也大打折扣。这里就跟大家分享一个非常优雅的树形菜单插件--ztree。
一、ztree的介绍
ztree是一个开源的“多功能的 jQuery 树插件”。最初由“jQTree”演变而来,而今已成为了jQuery生态中最受欢迎的树插件之一。ztree插件通过HTML+CSS+JS实现,可以实现多个复杂的交互功能,比如 编辑、拖拽、异步加载、异步搜索、异步提交、自定义图标等等。ztree提供了多个主题和多种皮肤,可以非常容易地进行配色和风格的调整。
二、ztree的应用场景
1、树形菜单:网站导航、左边菜单、树形菜单等。
2、组织结构图:公司组织架构图、政府机构架构图、知识库、部门架构等。
3、城市联动:省市区联动、请选择城市等。
4、文件夹目录树:文档管理、图片管理、音乐管理等。
5、分类标签:产品分类、文章标签、分类目录等。
三、ztree的特性
1、支持多层级数据结构,最多支持99层。
2、支持异步加载数据,解决了大数据量的数据加载速度问题。
3、支持鼠标右键、键盘操作,方便用户的操作。
4、支持多选、单选、拖拽等交互功能,提升用户使用体验。
5、提供了多个主题和皮肤,可以自由切换。
6、支持IE6及以上版本的浏览器,兼容性很不错。
四、ztree的应用实例
下面我们来看几个具体的应用实例。
1、示例一:基本树形菜单
代码示例:
```
var zNodes = [
{name:"父节点1", open:true, children:[
{name:"子节点1"},
{name:"子节点2"},
{name:"子节点3"},
]},
{name:"父节点2", open:true, children:[
{name:"子节点1"},
{name:"子节点2"},
{name:"子节点3"},
]},
{name:"父节点3", open:true, children:[
{name:"子节点1"},
{name:"子节点2"},
{name:"子节点3"},
]}
];
var setting = {};
setting = {
view: {
dblClickExpand: false,
showLine: true,
selectedMulti: false
},
data: {
simpleData: {
enable:true,
idKey: "id",
pIdKey: "pid",
rootPId: ""
}
}
};
$(document).ready(function(){
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
});
```
效果图:

2、示例二:异步加载数据
代码示例:
```
var setting = {
async: {
enable: true,
url:"xxx.do", //数据接口路径
autoParam:["id", "name=n", "level=lv"],
otherParam:{"otherParam":"zTreeAsyncTest"},
dataFilter: filter //数据过滤器
}
};
function filter(treeId, parentNode, childNodes) {
if (!childNodes) return null;
for (var i=0, l=childNodes.length; i childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.'); } return childNodes; } $(document).ready(function(){ $.fn.zTree.init($("#treeDemo"), setting); }); ``` 效果图:  3、示例三:自定义图标和节点样式 代码示例: ```
var zNodes = [
{name:"父节点1 - 展开", open:true, iconSkin:"pIcon01"},
{name:"父节点2 - 折叠", iconSkin:"pIcon02"},
{name:"父节点3 - 没有子节点", isParent:true, iconSkin:"pIcon03"},
{name:"父节点4 - 没有子节点", isParent:true, iconSkin:"pIcon03"},
{name:"父节点5 - 隐藏", isHidden:true, iconSkin:"pIcon04"}
];
var setting = {};
setting = {
view: {
addHoverDom: addHoverDom,
removeHoverDom: removeHoverDom,
dblClickExpand: false,
showLine: true,
selectedMulti: false
},
data: {
simpleData: {
enable:true
}
}
};
function addHoverDom(treeId, treeNode) {
var sObj = $("#" + treeNode.tId + "_span");
if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length>0) return;
var addStr = "";
sObj.after(addStr);
var btn = $("#addBtn_"+treeNode.tId);
if (btn) btn.bind("click", function(){
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
zTree.addNodes(treeNode, {id:(100 + Math.random()*100),pId:treeNode.id,name:"new node - " + Math.random().toString(36).substr(2)});
return false;
});
};
function removeHoverDom(treeId, treeNode) {
$("#addBtn_"+treeNode.tId).unbind().remove();
};
$(document).ready(function(){
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
});
```
效果图:

四、ztree的使用
1、入门
在使用ztree之前,我们需要先引入ztree的js和css文件,具体如下:
```
//css文件
//js文件
```
完整的入门页面代码如下:
```
var zNodes =[
{name:"父节点1", open:true, children:[
{name:"子节点1"},
{name:"子节点2"},
{name:"子节点3"},
{name:"子节点4"}
]},
{name:"父节点2", open:true, children:[
{name:"子节点1"},
{name:"子节点2"},
{name:"子节点3"},
{name:"子节点4"}
]},
{name:"父节点3", open:true, children:[
{name:"子节点1"},
{name:"子节点2"},
{name:"子节点3"},
{name:"子节点4"}
]}
];
var setting = {};
setting = {
view: {
dblClickExpand: false,
showLine: true,
selectedMulti: false
},
data: {
simpleData: {
enable:true,
idKey: "id",
pIdKey: "pid",
rootPId: ""
}
}
};
$(document).ready(function(){
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
});
```
2、配置项
在ztree中,提供了许多配置项来满足不同的需求。下面我们来解释一下其中比较常用的一些配置项。
(1)view
view配置项主要用于定义ztree外观和功能的展现,具体可以配置的参数及含义如下:
```
{
showLine: false, //是否显示连接线
showIcon: true, //是否显示节点的图标
showTitle: true, //是否显示title信息
fontCss: {}, //字体样式
dblClickExpand: true, //双击节点时,是否展示节点下的子节点
expandSpeed: "normal", //节点展开速度,支持 "slow"、"normal"、"fast" !
selectedMulti: true, //是否允许同时选中多个节点
nameIsHTML: false, //节点名称是否支持HTML标记
txtSelectedEnable: false //节点名称是否允许选中
addHoverDom: function(treeId, treeNode){}, //根据zTree ID和节点数据理定义鼠标hover展示的内容的函数
removeHoverDom: function(treeId, treeNode){} //根据zTree ID和节点数据删除hover展示的内容的函数
}
```
需要注意的是,当我们使用自定义图标时,需要给需要加图标的节点添加一个属性iconSkin,指定该节点的图标class。
(2)data
data配置项主要用于定义ztree数据结构的配置,具体可以配置的参数及含义如下:
```
{
simpleData: { //简单数据格式: id、pId使用自定义名称(默认为id和pId),且数据可以使用json数组格式
enable: true,
idKey: "id",
pIdKey: "pid",
rootPId: ""
},
key: { //节点数据中节点名称的属性配置,不配置则默认为"name"
name: "name"
}
}
```
需要注意的是,当我们使用简单数据格式时,需要将数据构建成以下的JSON格式:
```
[
{id:1, pId:0, name:"父节点1", open:true},
{id:101, pId:1, name:"子节点1"},
{id:102, pId:1, name:"子节点2"},
{id:2, pId:0, name:"父节点2", open:false},
{id:201, pId:2, name:"子节点1"},
{id:202, pId:2, name:"子节点2"}
];
```
(3)async
async配置项主要用于异步构建ztree树结构,具体可以配置的参数及含义如下:
```
{
enable: true, //是否开启异步模式
contentType: "application/x-www-form-urlencoded", //发送信息至服务器时内容编码类型
dataType: "text", //服务器返回的数据类型,包括HTML、XML、JSON、text等
type: "post", //请求方式(POST/GET)
url: "?action=xx", //数据源
autoParam: ["id", "name"], //Ajax请求参数,不需要可以不设置
dataFilter: function(treeId, parentNode, responseData){}, //返回数据经过处理的函数(处理Ajax请求得到的数据),并返回数据
otherParam: { //Ajax其他附带参数
"otherParam":"zTreeAsyncTest"
}
}
```
需要注意的是,当我们开启异步模式时,需要在zNodes数据中加入isParent属性。
3、异步加载数据
在使用ztree的过程中,经常会遇到数据量很大的情况,这时如果直接全部加载数据,就很容易遇到浏览器加载缓慢的问题。针对这个问题,ztree提供了一种名为“异步加载”的方式,可以仅根据用户的需求加载数据,从而提升了数据加载效率。
异步加载数据分为两种方式:简单数据(静态)和JSON数据(动态)。
(1)简单数据(静态)
在这种情况下,适用于数据量极小的情况,可将所有的数据放到zNodes里面。
具体步骤如下:
1、定义异步加载的异步url。
```
var url = "./data.json";
```
2、绑定异步加载调用
```
var setting = {
async: {
enable: true, //开启异步加载
url: url, //异步url
type: "get", //异步请求的方式
dataFilter: filter //数据过滤器
},
view: {
dblClickExpand: false //双击节点展开子节点
},
data: {
simpleData: {
enable: true, //开启简单数据格式
idKey: "id", //自定义简单数据格式中的id属性名称
pIdKey: "pid", //自定义简单数据格式中的pid属性名称
rootPId: "" //自定义根节点的pid属性值
}
}
};
function filter(treeId, parentNode, childNodes) {
if (!childNodes) return null;
for (var i=0, l=childNodes.length; i childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.'); } return childNodes; } $(document).ready(function(){ $.fn.zTree.init($("#treeDemo"), setting, zNodes); }); ``` 注意:在上面的代码中,filter函数可用于过滤返回的JSON数据。我们可以在该函数中对返回的数据进行处理,比如替换节点属性名称等操作。 (2)JSON数据(动态) 如果我们的数据量很大,这时候静态加载显然不能满足需求,因此ztree还提供了使用异步方式加载JSON数据的功能。 具体步骤如下: 1、定义异步加载的异步url。 ``` var url = "./data.json"; ``` 2、绑定异步加载调用 ``` var setting = { async: { enable: true, url: url, type: "get", autoParam: ["id", "name=n", "level=lv"], otherParam: {"otherParam":"zTreeAsyncTest"}, dataFilter: filter }, view: { dblClickExpand: false }, data: { simpleData: { enable: true, idKey: "id", pIdKey: "pid", rootPId: "" } } }; function filter(treeId, parentNode, childNodes) { if (!childNodes) return null; for (var i=0, l=childNodes.length; i childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.'); } return childNodes; } $(document).ready(function(){ $.fn.zTree.init($("#treeDemo"), setting); }); ``` 注意:在上面的代码中,autoParam参数用于设置异步请求时需要携带的参数,这里包括3个参数,分别是id、name、level,这些参数值可以在服务器端直接接收到。 五、总结 ztree作为一种树形菜单的实现方案,具备了优秀的性能和良好的功能特性,得到了开发者的广泛认可。与传统的树形菜单相比,ztree的优势在于它可以支持较为复杂的数据结构的展示和交互,解决了传统工程中树形菜单的诸多不足。同时,ztree插件支持自定义图标、外部操作(如新增节点等)、