zTree
简介
zTree
的API
文档:http://www.treejs.cn/v3/api.php
zTree
的在线示例:http://www.treejs.cn/v3/demo.php
树形控件的使用是应用开发过程中必不可少的。zTree
是一个依靠 jQuery
实现的多功能树插件。优异的性能、灵活的配置、多种功能的组合是 zTree
最大优点。
zTree
的特点
- 最新版的
zTree
将核心代码按照功能进行了分割,不需要的代码可以不用加载,如普通使用只需要加载核心的jquery.ztree.core-3.5.js
,需要使用勾选功能加载jquery.ztree.excheck-3.5.min.js
,需要使用编辑功能加载jquery.ztree.exedit-3.5.min.js
- 采用了延迟加载技术,上万节点轻松加载,即使在
IE6
下也能基本做到秒杀- 兼容
IE
、FireFox
、Chrome
、Opera
、Safari
等浏览器- 支持
JSON
数据- 支持静态 和
Ajax
异步加载节点数据- 支持任意更换皮肤 / 自定义图标(依靠
css
)- 支持极其灵活的
checkbox
或radio
选择功能- 提供多种事件响应回调
- 灵活的编辑(增/删/改/查)功能,可随意拖拽节点,还可以多节点拖拽
- 在一个页面内可同时生成多个
Tree
实例- 简单的参数配置实现,灵活多变的功能
zTree
文件介绍从zTree
官网下载的zTree
包括以下组成部分
metroStyle
文件夹:zTree
的metro
风格样式相关文件(图片及css
样式表)。zTreeStyle
文件夹:zTree
的标准风格样式文件夹(图片及css
样式表)js
文件:zTree.all.js
是完整的js
库,可单纯加载此文件实现所有zTree
功能,ztree.core、ztree.excheck、ztree.exedit、ztree.exhide
是对ztree
按照功能进行的分割,分别对应基本功能、复选功能、编辑功能、显隐功能。
zTree
的基本使用zTree
的创建在页面中添加对zTree
的js
及css
引用,由于zTree
基于JQuery
,JQuery
的引用是必须的。
DOCTYPE html>
<HTML>
<HEAD>
<TITLE> ZTREE DEMO TITLE>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="zTreeStyle/zTreeStyle.css" type="text/css">
<script type="text/javascript" src="jquery-1.4.2.js">script>
<script type="text/javascript" src="jquery.ztree.core-3.x.js">script>
<SCRIPT LANGUAGE="JavaScript">
var zTreeObj;
var setting = {}; // zTree 的参数配置,后面详解
var zNodes = [ // zTree 的数据属性,此处使用标准json格式
{
name: "test1", open: true, children: [
{ name: "test1_1" }, { name: "test1_2" }]
},
{
name: "test2", open: true, children: [
{ name: "test2_1" }, { name: "test2_2" }]
}
];
$(document).ready(function () {
zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, zNodes); //初始化zTree,三个参数一次分别是容器(zTree 的容器 className 别忘了设置为 "ztree")、参数配置、数据源
});
SCRIPT>
HEAD>
<BODY>
<div>
<ul id="treeDemo" class="ztree">ul>
div>
BODY>
HTML>
运行结果如下:
zTree
的配置zTree
的配置采用JSON
格式,按照配置的类型分为view
(可视界面相关配置)、data
(数据相关配置)、check
(复选框相关配置)、callback
(各类事件的回调函数配置)、async
(zTree
异步加载配置),一下是我们经常会使用到的一些配置及说明,其他详细配置可以参考zTree
官方API
文档的详细介绍。
var setting = {
view: {
selectedMulti: true, //设置是否能够同时选中多个节点
showIcon: true, //设置是否显示节点图标
showLine: true, //设置是否显示节点与节点之间的连线
showTitle: true, //设置是否显示节点的title提示信息
},
data: {
simpleData: {
enable: false, //设置是否启用简单数据格式(zTree支持标准数据格式跟简单数据格式,上面例子中是标准数据格式)
idKey: "id", //设置启用简单数据格式时id对应的属性名称
pidKey: "pId" //设置启用简单数据格式时parentId对应的属性名称,ztree根据id及pid层级关系构建树结构
}
},
check:{
enable: true //设置是否显示checkbox复选框
},
callback: {
onClick: onClick, //定义节点单击事件回调函数
onRightClick: OnRightClick, //定义节点右键单击事件回调函数
beforeRename: beforeRename, //定义节点重新编辑成功前回调函数,一般用于节点编辑时判断输入的节点名称是否合法
onDblClick: onDblClick, //定义节点双击事件回调函数
onCheck: onCheck //定义节点复选框选中或取消选中事件的回调函数
},
async: {
enable: true, //设置启用异步加载
type: "get", //异步加载类型:post和get
contentType: "application/json", //定义ajax提交参数的参数类型,一般为json格式
url: "/Design/Get", //定义数据请求路径
autoParam: ["id=id", "name=name"] //定义提交时参数的名称,=号前面标识节点属性,后面标识提交时json数据中参数的名称
}
};
需要注意的是,zTree
的事件回调部分,基本上每一个事件都对应一个beforeXXX
事件,比如onClick
事件对应有一个beforeOnClick
事件,主要用于控制相关事件是否允许执行,如果before
事件返回false
,则取消执行对应相关事件。
zTree
的数据格式zTree
的每一个节点都是一个treeNode
对象,treeNode
对象经常用到的属性和方法如下:
treeNode: {
name, //节点显示的文本
checked, //节点是否勾选,ztree配置启用复选框时有效
open, //节点是否展开
icon, //节点的图标
iconOpen, //节点展开式的图标
iconClose, //节点折叠时的图标
id, //节点的标识属性,对应的是启用简单数据格式时idKey对应的属性名,并不一定是id,如果setting中定义的idKey:"zId",那么此处就是zId
pId, //节点parentId属性,命名规则同id
children, //得到该节点所有孩子节点,直接下级,若要得到所有下属层级节点,需要自己写递归得到
isParent, //判断该节点是否是父节点,一般应用中通常需要判断只有叶子节点才能进行相关操作,或者删除时判断下面是有子节点时经常用到。
getPath() //得到该节点的路径,即所有父节点,包括自己,此方法返回的是一个数组,通常用于创建类似面包屑导航的东西A-->B-->C
}
zTree
的数据源一般有标准数据格式、简单数据格式两种,标准数据格式通过指定节点的chidren
属性构建层级关系,而简单数据格式根据根据id
,pid
属性构建层级关系,我们在应用开发中使用关系型数据库,一般采用的都是简单数据格式。
var nodes = [
{name: "父节点1", children: [
{name: "子节点1"},
{name: "子节点2"}
]}
];
var nodes = [
{id:1, pId:0, name: "父节点1"},
{id:11, pId:1, name: "子节点1"},
{id:12, pId:1, name: "子节点2"}
];
zTree
的常用方法zTree
对象var treeObj = $.fn.zTree.getZTreeObj("tree");
addNodes(parentNode,index,newNodes,isSlient)
parentNode
:指定的父节点,如果增加根节点,请设置parentNode
为null
即可
index
:新节点插入的位置(从0
开始),index = -1
时,插入到最后,此参数可忽略
newNodes
:需要增加的节点数据JSON
对象集合,数据只需要满足zTree
的节点数据必需的属性即可
isSilent
:true
时,添加节点后不展开父节点,其他值或缺省状态都自动展开
checkAllNodes(checked);
checked
参数为true
时全部勾选,为false
时全部取消勾选。
checkNode(node, checked, checkedTypeFlag,callbackFlag);
node
:要进行操作的节点
checked
:为true
勾选,为false
取消勾选
checkeTypeFlag
:为true
表示对当前结点的子节点及父节点进行勾选状态的联动,为false
不联动
callbackFlag
:为true
时表示执行beforeOnCheck
和onCheck
事件的回调函数,为false
不执行
edit(node);
使节点处于编辑状态,必须引用jquery.ztree.exedit
扩展。
expandAll(expand);
expand
为true
是展开所有节点,为false
是折叠所有节点。
getNodesByParam(key,value, parentNode);
key
:属性名
value
:属性值
parentNode
:是否在指定节点下查找,为null
表示整个树查找。
getCheckedNodes(checked);
checked
为true
表示获取所有被勾选的节点集合,为false
表示所有未被勾选的节点集合
getChangeCheckedNodes()
zTree
的常用操作ajax
请求数据并创建zTree
$(function () {
var setting = { //此处根据自己需要进行配置
view: {
selectedMulti: false
},
data: {
simpleData: {
enable: true
}
},
callback: {
onClick: onDesignTreeClick,
onRightClick: OnRightClick,
beforeRename: beforeRename,
onCheck:onCheck
}
};
$.ajax({
type: "Get",
url: "/Design/GetDesignTreeData", //ajax请求地址
success: function (data) {
$.fn.zTree.init($("#treeZo"), setting, data); //加载数据
},
});
});
后台代码如下,可以根据需要返回你想要的任何数据,绑定到zTree
上,然后通过treeNode
.属性名取到对应的值,实现一些界面逻辑操作。
public ActionResult GetDesignTreeData() {
var result = _designAppService.GetDesignTreeData();
List<ModelTreeViewModel> treeModels = new List<ModelTreeViewModel>();
bool open = false;
foreach (var design in result.Designs)
{
if (design.ParentId == Guid.Empty)
open = true;
else open = false;
treeModels.Add(new ModelTreeViewModel() { Id = design.Id.ToString(), PId = design.ParentId.ToString(), Name = design.Name, Open = open, Data = design.Remarks ?? "", ViewPoint = design.ViewPoint ?? "", Checked = true });
}
return Json(treeModels, JsonRequestBehavior.AllowGet);
}
节点单击事件会捕获事件对象e
,zTree
的唯一标识treeId
,当前选中的节点对象treeNode
三个参数。根据实际需求可获取treeNode
中包含的任何属性数据,进行相关操作
function onClick(e, treeId, treeNode) {
if (treeNode.isParent) //如果不是叶子结点,结束
return;
alert(treeNode.name); //获取当前结点上的相关属性数据,执行相关逻辑
};
一般情况下我们会直接使用treeObj.getCheckedNodes(true)
获取所有选中的节点,然后遍历所有选中的节点进行相关操作,当面对大数据量时,这种操作方法便不可取,可通过getChangeCheckedNodes()
方法获取勾选状态被改变的节点集合,值针对状态改变的节点做相应处理。
function onCheck() {
var treeObj = $.fn.zTree.getZTreeObj("treeDemo"); //获取树对象
var nodes = treeObj.getChangeCheckedNodes(); //获取勾选状态改变的节点
var designIds = [];
var status = 0; //定义初始勾选状态为未勾选
if (nodes[0].checked)
status = 1; //如果状态改变节点为勾选状态,说明当前操作是从未勾选变为已勾选。
$.each(nodes, function (i, item) {
designIds.push(item.id); //将状态改变的节点id输出到数组
item.checkedOld = item.checked; //这句话很关键,将节点的初始状态置为当前状态。否则每次勾选操作获取状态改变节点时只会跟树初始化的状态相比较。
})
$.ajax({
type: "Post",
url: "/Design/GetRelationComponentIdsByDesigns",
data: { "designIds": designIds },
success: function (data) {
RealBimOcx.BatchAddSubClrInfoBegin();
$.each(data.result, function (i, item) {
if (status == 1) //这里根据发生改变的节点是勾选还是为勾选进行相关逻辑操作。
RealBimOcx.AddSubClrInfo(item, 255, 255, 0);
else
RealBimOcx.AddSubClrInfo(item, 0, 255, 0);
if (i % 100 == 0) {
RealBimOcx.BatchAddSubClrInfoEnd();
RealBimOcx.BatchAddSubClrInfoBegin();
}
})
RealBimOcx.BatchAddSubClrInfoEnd();
}
})
};
zTree
的右键增删改操作<div id="rMenu" style="z-index:100;">
<ul>
<li id="m_add" onclick="addTreeNode();">新增节点li>
<li id="m_del" onclick="removeTreeNode();">删除节点li>
<li id="m_edit" onclick="editTreeNode();" style="border-bottom:1px solid #cecece">编辑节点li><li id="m_left">升级li>
<li id="m_right">降级li>
<li id="m_up">上移li>
<li id="m_down" style="border-bottom:1px solid #cecece">下移li>
<li id="m_reset" onclick="resetTree();">重置节点li>
<li id="m_open" onclick="treeOpen()">展开所有li>
<li id="m_stop" onclick="treeStop()">收起所有li>
ul>
div>
zTree
右键单击事件回调函数//右键单击回调函数
function OnRightClick(event, treeId, treeNode) {
$("#treeZo").hide();
if (!treeNode && event.target.tagName.toLowerCase() != "button" && $(event.target).parents("a").length == 0) {
zTree.cancelSelectedNode();
showRMenu("root", event.clientX, event.clientY); //根据鼠标位置显示右键操作面板
} else if (treeNode && !treeNode.noR) {
zTree.selectNode(treeNode);
showRMenu("node", event.clientX, event.clientY);
}
$("#treeZo").show();
}
//根据节点类型,控制右键操作菜单哪些可用哪些不可用
function showRMenu(type, x, y) {
$("#rMenu ul").show();
if (type == "root") {
$("#m_del").hide();
$("#m_edit").hide();
$("#m_left").hide();
$("#m_right").hide();
$("#m_up").hide();
$("#m_down").hide();
$("#m_add").addClass('mboder');
} else {
$("#m_del").show();
$("#m_edit").show();
$("#m_left").show();
$("#m_right").show();
$("#m_up").show();
$("#m_down").show();
$("#m_add").removeClass('mboder');
}
rMenu.css({ "top": y + "px", "left": x + "px", "visibility": "visible" });
$("body").bind("mousedown", onBodyMouseDown);
}
//以藏右键面板
function hideRMenu() {
if (rMenu) rMenu.css({ "visibility": "hidden" });
$("body").unbind("mousedown", onBodyMouseDown);
}
//单击页面其他位置 隐藏右键面板
function onBodyMouseDown(event) {
if (!(event.target.id == "rMenu" || $(event.target).parents("#rMenu").length > 0)) {
rMenu.css({ "visibility": "hidden" });
}
}
//增加节点
function addTreeNode() {
hideRMenu();
var name = new Date().getTime(); //利用时间戳生成节点名称,保证节点名称唯一
var newNode = {
name: name
};
if (zTree.getSelectedNodes()[0]) {
newNode.checked = zTree.getSelectedNodes()[0].checked;
newNode.pid = zTree.getSelectedNodes()[0].id;
zTree.addNodes(zTree.getSelectedNodes()[0], newNode);
} else {
zTree.addNodes(null, newNode);
}
var node = zTree.getNodeByParam("name", name, null); //得到新增加的节点
zTree.selectNode(node); //选中新增加的节点
zTree.editName(node); //让新增加的节点处于编辑状态
}
function editTreeNode() {
var nodes = zTree.getSelectedNodes(); //得到选中节点集合
if (nodes && nodes.length > 0) {
var parent = nodes[0].getParentNode(); //得到选中节点的父节点
if (parent) {
nodes[0].pid = parent.id; //如果选中节点父节点存在,将当前结点的pid属性值设置为父节点的id
}
zTree.editName(nodes[0]); //让选中节点处于编辑状态
}
hideRMenu(); //隐藏右键面板
};
//编辑并保存节点
function beforeRename(treeId, treeNode, newName, isCancel) {
if (newName.length == 0) { //节点名称判断
alert("不能为空。");
return false;
}
else {
$.ajax({ //数据入库
type: "Post",
url: "/Design/InsertOrUpdate",
data: { "dto": { "Id": treeNode.id, "ParentId": treeNode.pid, "Name": newName } },
success: function (data) {
if (data.result == "Faild") {
layerAlert("保存失败。");
return false;
}
else {
treeNode.id = data.result; //将返回的id赋值给当前结点
return true;
}
}
});
}
};
function removeTreeNode() {
hideRMenu();
var nodes = zTree.getSelectedNodes();
if (nodes && nodes.length > 0) {
if (nodes[0].children && nodes[0].children.length > 0) {
alert("包含下级,无法删除。");
} else {
if (confirm("该操作会将关联数据同步删除,是否确认删除?") == true) {
$.ajax({
type: "Post",
url: "/Design/Delete",
data: { "id": nodes[0].id },
success: function (data) {
if (data.result == "Success") {
zTree.removeNode(nodes[0]);
}
else {
alert("删除失败。");
}
}
});
};
}
}
};
我们通常使用到树形控件做授权或关联类似的操作,一般会先全部取消勾选,然后根据选中的数据关联对树控件的复选框进行选中操作,在大数据量时,大约几万条数据,全部取消勾选+
根据关联数据勾选相关节点这个操作通过js
执行会很慢,这种情况建议在后台通过关联关系重新组织zTree
需要的数据源,对每条数据(对应树节点)设置checked
属性,然后再前台页面重新加载树,这种操作速度要快得多。
$.ajax({
type: "Get",
url: "/Model/GetRelationModelTreeData?designId=" + treeNode.id + "&t=" + new Date(),
success: function (data) {
//$.each(data.result, function (i, item) {
// var node = modelTree.getNodeByParam("id", item, null);
// modelTree.checkNode(node, true, true);
//});
$.fn.zTree.init($("#treejian"), setting1, data.result); //改为重新加载,比js循环勾选速度要快。
}
});
本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞收藏关注✨,一起加油☕