Ztree 是一种树形展示,当你用新型前端框架的时候,你就意味着要学习他的树形展示,但是Ztree它单独自成一体,这样就不用总是学习别的树形展示了,学会Ztree,可以通用;
优点:
1.优异的性能
2.灵活的配置
3.多种功能的组合
适合项目开发
1.树状菜单
2.树状数据的Web显示
3.权限管理等等。
特点:
● zTree v3.0 将核心代码按照功能进行了分割,不需要的代码可以不用加载
● 采用了延迟加载技术,上万节点轻松加载,即使在 IE6 下也能基本做到秒杀
● 兼容 IE、FireFox、Chrome、Opera、Safari 等浏览器
● 支持 JSON 数据
● 支持静态和 Ajax 异步加载节点数据
● 支持任意更换皮肤 / 自定义图标(依靠css)
● 支持极其灵活的 checkbox 或 radio 选择功能
● 提供多种事件响应回调
● 灵活的编辑(增/删/改/查)功能,可随意拖拽节点,还可以多节点拖拽哟
● 在一个页面内可同时生成多个 Tree 实例
● 简单的参数配置实现 灵活多变的功能
一、网站地址
1.Ztree官网:(官网API文档以及Demo演示项方法介绍比较详细)(重点)
http://www.treejs.cn/v3/main.php#_zTreeInfo
2.进阶学习网页原地址:(学习博客)
http://www.cnblogs.com/sylvandu/p/5805592.html
3.入门学习网页原地址:(学习博客)
https://www.toutiao.com/a6519719172337828365/
4. 资源下载地址:(文件夹已有名称为:zTree资料包)(重点)
https://gitee.com/zTree/zTree_v3
5.JQUery下载官网:
https://code.jquery.com/jquery/
6.为知个人笔记(可以把需要记录的笔记写在里面)
https://note.wiz.cn/
7.zTree贴吧 (百度贴吧)
https://tieba.baidu.com/f?kw=ztree
二、关键性代码
zTree加载需要注意的地方
简单格式:
必须项 :
是否为父节点Isparent、节点id、 节点Pid、节点名name
次需 :
是否打开(针对于父节点) open、参数 attribute
扩展项:
icon 图片等等
基本格式:
必须项 :
是否为父节点Isparent、节点id、 节点Pid、节点名name
Children 子级节点集合。
次需:
是否打开(针对于父节点) open、参数 attribute
扩展项目:……
2.初始化zTree方法
介绍 :万物(恶)之源
简介:这个方法是用来加载指定JSON数据的,nodes则是数据名
.fn.zTree.init( .fn.zTree.init(.fn.zTree.init(("#treeDemo"), setting,nodes);
简介:这个方法时拿来加载数据库的无需nodes
.fn.zTree.init( .fn.zTree.init(.fn.zTree.init(("#treeDemo"), setting); //arg1:zTree对象页面展示ID,arg2 ztree展示设置。
三、踩到的坑
1.前端F12调试控制台显示:$… is not a function
这个错误弄了半个小时,因为什么呢?因为zTree和EasyUi各有JQuery文件,因为各自都依赖于JQuery,所以里面的JQuery版本不一样,导入的JQuery文件冲突,删除EasyUi里的JQuery就行了。
也有另外一个原因,是因为进行上一步操作后JQuery顺序不正确。
PS:所以直接把JQuery导入放到第一个,这就万无一失了。
2.空的父节点无限重新加载tree
当然我写的这个问题的解决方法,只针对于你做zTree菜单并且使用简单JSON格式方法去展示的时候,当你点开一个空的父节点的时候,它会又把当前的这个tree菜单又加载一遍,然后作为这个空父节点的子节点展示出来,如果遇到这种问题,请你放弃使用简单格式,老老实实用普通JSON格式。
错误图片(来自前端F12调试的控制台):
控制台的Bug:
这个错误挺有意识的,为什么会出现这个错误呢,仔细看你异步加载时候提交方式如何设置的就知道了,当提交方式为get它就来这个错误了,改成post就没有问题了。
四、 子节点无法找到父节点
这个问题也是出现在你使用简单JSON格式来展示你的tree的时候,因为简单格式的ztree 后端返回的JSOn格式并没有定义children这个属性,但是ztree它是可以通过设置支持简单格式的。如图:
当你设置enable为false,它的子节点的就无法查询到父节点了,所以你把enable 设置为 true ,就?了。
Ztree 的Dao层
/**
- 树形菜单Ztree数据访问层
- @author Administrator
*/
public class ZtreeDao extends JSonBaseDao {
// 第一种 : 简单JSOn格式,通过pid以及id判断
/**
* 拿到菜单栏
*
* @param parameter
* @return
* @throws SQLException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
*/
private List<Map<String, Object>> menuList(Map<String, String[]> parameter) throws SQLException,
InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
String sql = "select * from tb_ztree_menu where true";
String parentid = JSonUtil.getReqParameter(parameter, "parentid");
if (StringUtils.isNotBlank(parentid)) {
sql += " and parentid = " + parentid;
}
return super.executeQuery(sql, null);
}
/**
* 将数据库查找出的数据转换为可展示数据
*
* @param map
* @param ztreeNode
*/
private void menuToJson(List<Map<String, Object>> menuList, List<ZtreeNode> ztreeNodeList) {
ZtreeNode ztreeNode = null;
if (menuList != null && menuList.size() > 0) {
for (Map<String, Object> map : menuList) {
ztreeNode = new ZtreeNode();
ztreeNode.setId(Integer.valueOf(map.get("menuId").toString()));
ztreeNode.setpId(Integer.valueOf(map.get("parentId").toString()));
ztreeNode.setName(map.get("menuName").toString());
ztreeNode.setIsParent(map.get("isParent").toString());
ztreeNode.setOpen(map.get("isParent").toString());
ztreeNode.setAttribute(map);
ztreeNodeList.add(ztreeNode);
}
}
}
/**
* 子控制器调用该查询方法
*
* @param parameter
* @return
* @throws SQLException
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public List<ZtreeNode> menuJsonList(Map<String, String[]> parameter) throws InstantiationException,
IllegalAccessException, NoSuchFieldException, SecurityException, SQLException {
List<Map<String, Object>> menuList = this.menuList(parameter);
List<ZtreeNode> ztreeNodeList = new ArrayList<>();
this.menuToJson(menuList, ztreeNodeList);
return ztreeNodeList;
}
// -----------------------------
// 第二种:标准JSOn格式,标准的 JSON 数据需要嵌套表示节点的父子包含关系
/**
* 将数据库所有的数据加载出来
*
* @param parameter
* @param pageBean
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
* @throws SQLException
*/
public List<Map<String, Object>> menuList(Map<String, String[]> parameter, PageBean pageBean)
throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException,
SQLException {
String sql = "select * from tb_ztree_menu where true";
String menuId = JSonUtil.getReqParameter(parameter, "menuId");
if (StringUtils.isNotBlank(menuId)) {
sql += " and parentId in ( " + menuId + ")";
} else {
sql += " and parentId = -1";
}
return super.executeQuery(sql, null);
}
/**
* 步骤: 一.查询所有的信息 二.直接查出来的数据不能展示,然后就需要将所有的数据转换成可展示数据 1.添加所有数据Node
* 2.如果当前节点是父节点,则用递归添加子节点 3.写方法啊,还看什么 三.递归方法 四.展示方法
*
*/
/**
* 将对象转换成可以展示的对象,此方法只针对于当前对象。 使用递归方法将所有对象转换完毕。
*
* @param menuList
* @param treeNode
* @throws SQLException
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public void menuToNode(Map<String, Object> map, ZtreeNode ztreeNode) throws InstantiationException,
IllegalAccessException, NoSuchFieldException, SecurityException, SQLException {
// 添加相应的值
ztreeNode.setId(Integer.valueOf(map.get("menuId").toString()));
ztreeNode.setpId(Integer.valueOf(map.get("parentId").toString()));
ztreeNode.setName(map.get("menuName").toString());
ztreeNode.setIsParent(map.get("isParent").toString());
ztreeNode.setAttribute(map);
// 定义数组(用来装载转换后的当前父节点的子节点对象数组)
List<ZtreeNode> treeNodeList = new ArrayList<>();
// 定义一个参数数组并且赋予当前节点的Id,用来查询当前父节点的子节点对象
Map<String, String[]> paramMap = new HashMap<>();
paramMap.put("menuId", new String[] { ztreeNode.getId() + "" });
// 开始查询当前父节点的子节点对象、并拿到返回集合
List<Map<String, Object>> menuChildrenList = this.menuList(paramMap, null);
// 如果该节点有子节点,那么就得进行子节点的转换操作 通俗点就是如果有儿子就要把儿子丢进去转换一波
if (menuChildrenList != null && menuChildrenList.size() > 0) {
ztreeNode.setIsParent("true");//不管数据库是否false与true,只要有子节点,那么设置它是父节点
ztreeNode.setOpen("true");//设置自动展开
// 把子节点对象丢过去转换一波
this.menuListToNodeList(menuChildrenList, treeNodeList);
}
// 这里是没有儿子的情况,当父节点没有儿子的时候,我们就把它的自动展开给覆盖,让它不自动展开
else {
ztreeNode.setOpen("false");// 是否默认打开跟是否为父节点时一样的,也就是打开所有父节点
}
// 将子节点对象添加到treeNode
ztreeNode.setChildren(treeNodeList);
}
/**
* 将当前父节点里所有的子节点转换成可以展示的对象,此方法只针对于当前父节点对象的子节点。
*
* @param menuList
* @param treeNodeList
* @throws SQLException
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public void menuListToNodeList(List<Map<String, Object>> menuList, List<ZtreeNode> treeNodeList)
throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException,
SQLException {
ZtreeNode treeNode = null;// 先声明一个对象
// 将参数menuList父节点的子节点遍历
for (Map<String, Object> tree : menuList) {
treeNode = new ZtreeNode();// 这里实例出来
// 当前对象(也就是当前父节点下所有的子节点),转换为可以展示的对象
// tree代表当前对象 treeNode代表转换后的对象
this.menuToNode(tree, treeNode);
// 然后将转换后的对象添加到集合里面去
treeNodeList.add(treeNode);
}
}
/**
* 展示方法 Action调用该方法
*
* @param parameter
* @param pageBean
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
* @throws SQLException
*/
public List<ZtreeNode> menuTreeList(Map<String, String[]> parameter, PageBean pageBean)
throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException,
SQLException {
// 首先调用查询方法把数据从数据库查出
List<Map<String, Object>> menuList = this.menuList(parameter, pageBean);
// 定义菜单数组
List<ZtreeNode> treeNodeList = new ArrayList<>();
// 转换一波
this.menuListToNodeList(menuList, treeNodeList);
return treeNodeList;// 返回数组,该数组即是所需数组
}
// -----------------------------
}