详解js树形控件—zTree使用总结


Posted in Javascript onDecember 28, 2016

0 zTree简介

树形控件的使用是应用开发过程中必不可少的。zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。

0.0 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 实例
  • 简单的参数配置实现,灵活多变的功能

0.1 zTree文件介绍

从zTree官网下载的zTree包括以下组成部分

详解js树形控件—zTree使用总结

  • metroStyle文件夹:zTree的metro风格样式相关文件(图片及css样式表)。
  • zTreeStyle文件夹:zTree的标准风格样式文件夹(图片及css样式表)
  • js文件:zTree.all.js是完整的js库,可单纯加载此文件实现所有zTree功能,ztree.core、ztree.excheck、ztree.exedit、ztree.exhide是对ztree按照功能进行的分割,分别对应基本功能、复选功能、编辑功能、显隐功能。

1 zTree的基本使用

1.0 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>

运行结果如下

详解js树形控件—zTree使用总结

1.1 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,则取消执行对应相关事件。

1.2 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的默认配置是不启用简单数据格式,使用简单数据格式一定要在setting中进行简单数据格式的相关配置。

1.3 zTree的常用方法

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()

2 zTree的常用操作

2.0 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);
  }

 2.1 节点单击操作

节点单击事件会捕获事件对象e,zTree的唯一标识treeId,当前选中的节点对象treeNode三个参数。根据实际需求可获取treeNode中包含的任何属性数据,进行相关操作

function onClick(e, treeId, treeNode) {
   if (treeNode.isParent) //如果不是叶子结点,结束
    return;
   alert(treeNode.name); //获取当前结点上的相关属性数据,执行相关逻辑
  };

2.2 节点复选框事件

一般情况下我们会直接使用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();

    }
   })
  };

 2.3 实现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>

详解js树形控件—zTree使用总结

实现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("删除失败。");
        }
       }
      });
     };
    }
   }
  };

2.4 一些总结

我们通常使用到树形控件做授权或关联类似的操作,一般会先全部取消勾选,然后根据选中的数据关联对树控件的复选框进行选中操作,在大数据量时,大约几万条数据,全部取消勾选+根据关联数据勾选相关节点这个操作通过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循环勾选速度要快。
   }
  });

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 页面载入进度条实现代码
Feb 08 Javascript
修复IE9&amp;safari 的sort方法
Oct 21 Javascript
通过Javascript创建一个选择文件的对话框代码
Jun 16 Javascript
Javascript实现页面跳转的几种方式分享
Oct 26 Javascript
javascript相等运算符与等同运算符详细介绍
Nov 09 Javascript
js中 javascript:void(0) 用法详解
Aug 11 Javascript
js生成随机数的方法实例
Oct 16 Javascript
AngularJS 单元测试(二)详解
Sep 21 Javascript
jQuery插件HighCharts绘制2D圆环图效果示例【附demo源码下载】
Mar 09 Javascript
webpack配置导致字体图标无法显示的解决方法
Mar 06 Javascript
React中使用UMEditor的方法示例
Dec 27 Javascript
解决 window.onload 被覆盖的问题方法
Jan 14 Javascript
js 轮播效果实例分享
Dec 28 #Javascript
JS正则RegExp.test()使用注意事项(不具有重复性)
Dec 28 #Javascript
Bootstrap 模态框实例插件案例分析
Dec 28 #Javascript
Angular使用ng-messages与PHP进行表单数据验证
Dec 28 #Javascript
Bootstrap中datetimepicker使用小结
Dec 28 #Javascript
html5+CSS 实现禁止IOS长按复制粘贴功能
Dec 28 #Javascript
angular-ui-sortable实现可拖拽排序列表
Dec 28 #Javascript
You might like
SONY SRF-40W电路分析
2021/03/02 无线电
php 字符过滤类,用于过滤各类用户输入的数据
2009/05/27 PHP
PHP SPL标准库之数据结构堆(SplHeap)简单使用实例
2015/05/12 PHP
php使用substr()和strpos()联合查找字符串中某一特定字符的方法
2015/05/12 PHP
PHP的命令行命令使用指南
2015/08/18 PHP
thinkPHP3.2.2框架行为扩展及demo示例
2018/06/19 PHP
Laravel中GraphQL接口请求频率实战记录
2020/09/01 PHP
完整显示当前日期和时间的JS代码
2007/09/17 Javascript
简单的JS多重继承示例
2008/03/13 Javascript
Ajax 数据请求的简单分析
2011/04/05 Javascript
jQuery EasyUI API 中文文档 - TimeSpinner时间微调器
2011/10/23 Javascript
jquery获取table中的某行全部td的内容方法
2013/03/08 Javascript
JavaScript通过function定义对象并给对象添加toString()方法实例分析
2015/03/23 Javascript
BootStrap selectpicker
2016/06/20 Javascript
网络传输协议(http协议)
2016/11/18 Javascript
node.js程序作为服务并在windows下开机自启动(用forever)
2017/03/29 Javascript
Node.js编写CLI的实例详解
2017/05/17 Javascript
利用JavaScript如何查询某个值是否数组内
2017/07/30 Javascript
ComboBox(下拉列表框)通过url加载调用远程数据的方法
2017/08/06 Javascript
[49:21]2018DOTA2亚洲邀请赛3月30日 小组赛B组 Effect VS iG
2018/03/31 DOTA
Python实现生成随机日期字符串的方法示例
2017/12/25 Python
python+opencv轮廓检测代码解析
2018/01/05 Python
Python3.6笔记之将程序运行结果输出到文件的方法
2018/04/22 Python
python实现ID3决策树算法
2018/08/29 Python
在python中将字符串转为json对象并取值的方法
2018/12/31 Python
python实现定时发送qq消息
2019/01/18 Python
html5配合css3实现带提示文字的输入框(摆脱js)
2013/03/08 HTML / CSS
美国牙科折扣计划:DentalPlans.com
2019/08/26 全球购物
传统软件工程与面向对象的软件工程有什么区别
2012/05/31 面试题
小学生成长感言
2014/01/30 职场文书
毕业晚会主持词
2014/03/24 职场文书
感恩父母的演讲稿
2014/05/06 职场文书
青春奉献演讲稿
2014/05/08 职场文书
小学生一分钟演讲稿
2014/08/26 职场文书
MySql学习笔记之事务隔离级别详解
2021/05/12 MySQL
动画电影《擅长捉弄人的高木同学》6月10日上映!
2022/03/20 日漫