zTree树节点的增删改查。

本文介绍了如何使用zTree实现分类层级关系的树节点操作,包括增加、修改、删除功能。重点在于多层级删除的实现,通过设置节点的acurl字段作为标识码,实现按层级删除子节点。文章提供了zTree的基础知识、核心参数、开发步骤及部分代码示例,适合需要进行树节点操作的开发者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近做一个项目,单纯用于分类的层级关系,并不是zTree的角色和权限,只是操作树的节点,对树的节点进行增加,修改,删除。

最近做一个项目,单纯用于分类的层级关系,并不是zTree的角色和权限,只是操作树的节点,对树的节点进行增加,修改,删除。

 csdn资源下载  http://download.youkuaiyun.com/detail/maxwell_chia/8343375

 

用的jQuery的zTree是从官网上下载的最新版本。

中文官网地址:http://www.ztree.me/hunter/zTree.html

我上传的包里有最新版本API及插件包。上面是网址,可以自行下载最新版本。当前时间是2015年1月。

API提供了 demo   很详细,我在这里只提供一种思路,仅供参考。

我的项目需求:对物品分类进行树形展示,并且可以无限层级关系,然后通过操作节点来对类别信息进行增删改查。

技术难点在于多层级的删除。这也是本文的亮点。

 

下图为API样式。

 

 

 

 

 

 

 

 

 

 

 

API的使用:

API提供了中英文两种 cn代表中文

 

 

首先我这里先给出一些树的基础知识,还有其他文档,为不同水平的朋友提供参考,希望大家去下载学习。

zTree 是利用 JQuery 的核心代码,实现一套能完成大部分常用功能的 Tree 插件

·  兼容 IE、FireFox、Chrome 等浏览器

·  在一个页面内可同时生成多个 Tree 实例

·  支持 JSON 数据

·  支持一次性静态生成 和 Ajax 异步加载 两种方式

·  支持多种事件响应及反馈

·  支持 Tree 的节点移动、编辑、删除

·  支持任意更换皮肤 / 个性化图标(依靠css)

·  支持极其灵活的 checkbox 或 radio 选择功能

·  简单的参数配置实现 灵活多变的功能

 

部分函数和属性介绍(其他核心参数参见api有详细展示

核心:zTree(setting, [zTreeNodes])

这个函数接受一个JSON格式的数据对象setting和一个JSON格式的数据对象zTreeNodes,从而建立 Tree。

核心参数:setting

zTree 的参数配置都在这里完成,简单的说:树的样式、事件访问路径等都在这里配置

setting 举例:

var setting = {     showLine: true,     checkable: true }; 

核心参数:zTreeNodes

zTree 的全部节点数据集合,采用由JSON对象组成的数据结构,简单的说:这里使用Json格式保存了树的所有信息

zTreeNodes的格式分为两种:利用Json格式嵌套体现父子关系和Array简单格式

①带有父子关系的标准 zTreeNodes 举例:

var zTreeNodes = [ 

   {"id":1, "name":"test1", "nodes":[       {"id":11, "name":"test11", "nodes":[         {"id":111, "name":"test111"}       ]},       {"id":12, "name":"test12"}     ]},     ...... ]; 

 

 

 

②带有父子关系的简单 Array 格式(isSimpleData)的 zTreeNodes 举例:

var treeNodes = [                                  

   {"id":1, "pId":0, "name":"test1"},     {"id":11, "pId":1, "name":"test11"},     {"id":12, "pId":1, "name":"test12"},     {"id":111, "pId":11, "name":"test111"},     ...... ]; 

 

 

开发步骤

前台页面部分

效果如上图 API里的demo,大家可以选取不同的demo样式及功能。

前台页面是直接拿的API里的demo的代码,只修改自己用到的功能,没用的功能无视他就行。



第一个功能树的显示:


<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

 <HEAD>

<TITLE> ZTREE DEMO - select menu</TITLE>

<meta http-equiv="content-type" content="text/html; charset=UTF-8">

<!-- ztree js -->

<link rel="stylesheet" href="<%=request.getContextPath()%>/res/news/gonggao/jdd/ztree/css/demo.css" type="text/css">

<link rel="stylesheet" href="<%=request.getContextPath()%>/res/news/gonggao/jdd/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">

<script type="text/javascript" src="<%=request.getContextPath()%>/res/news/gonggao/jdd/ztree/js/jquery-1.4.4.min.js"></script>

<script type="text/javascript" src="<%=request.getContextPath()%>/res/news/gonggao/jdd/ztree/js/jquery.ztree.core-3.5.js"></script>

<script type="text/javascript" src="<%=request.getContextPath()%>/res/news/gonggao/jdd/ztree/js/jquery.ztree.excheck-3.5.js"></script>

<script type="text/javascript" src="<%=request.getContextPath()%>/res/news/gonggao/jdd/ztree/js/jquery.ztree.exedit-3.5.js"></script>

<SCRIPT type="text/javascript">

var setting = {

data: {

simpleData: {

enable: true,

idKey: "id",

pIdKey: "pId",

rootPId: 0

}

},

view: {

dblClickExpand: false

},

check: {

enable: true

},

callback: {

onRightClick: OnRightClick

}

};

 

var zNodes =${json};

 

function OnRightClick(event, treeId, treeNode) {

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

}

}

 

function showRMenu(type, x, y) {

$("#rMenu ul").show();

if (type=="root") {

$("#m_del").hide();

$("#m_check").hide();

$("#m_unCheck").hide();

else {

$("#m_del").show();

$("#m_check").show();

$("#m_unCheck").show();

}

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

}

}

var addCount = 1;

function addTreeNode() {

hideRMenu();

var newNode = { name:"newNode " + (addCount++)};

if (zTree.getSelectedNodes()[0]) {

newNode.checked = zTree.getSelectedNodes()[0].checked;

zTree.addNodes(zTree.getSelectedNodes()[0], newNode);

else {

zTree.addNodes(null, newNode);

}

}

function updateTreeNode() {

hideRMenu();

var nodes = zTree.getSelectedNodes();

var msg = "If you update this node ? \n\nPlease confirm!";

if (confirm(msg)==true){

var ckid=nodes[0].id;

alert(ckid)

window.location.href = "<c:url value='/ac/updateFac.do?acid='/>"+ckid;

//zTree.removeNode(nodes[0]);

}

if (zTree.getSelectedNodes()[0]) {

newNode.checked = zTree.getSelectedNodes()[0].checked;

zTree.addNodes(zTree.getSelectedNodes()[0], newNode);

else {

zTree.addNodes(null, newNode);

}

}

function removeTreeNode() {

hideRMenu();

var nodes = zTree.getSelectedNodes();

if (nodes && nodes.length>0) {

if (nodes[0].children && nodes[0].children.length > 0) {

var msg = "你是要干掉当前节点及其子节点吗 ?  \n\nPlease confirm!";

if (confirm(msg)==true){

var ckid=nodes[0].id;

alert(ckid)

window.location.href = "<c:url value='/ac/delFac.do?acid='/>"+ckid;

//zTree.removeNode(nodes[0]);

}

else {

var ckid=nodes[0].id;

alert(ckid)

window.location.href = "<c:url value='/ac/delFac2.do?acid='/>"+ckid;

}

}

}

function checkTreeNode(checked) {

var nodes = zTree.getSelectedNodes();

if (nodes && nodes.length>0) {

zTree.checkNode(nodes[0], checked, true);

}

hideRMenu();

}

function resetTree() {

hideRMenu();

$.fn.zTree.init($("#treeDemo"), setting, zNodes);

}

 

var zTree, rMenu;

$(document).ready(function(){

$.fn.zTree.init($("#treeDemo"), setting, zNodes);

zTree = $.fn.zTree.getZTreeObj("treeDemo");

rMenu = $("#rMenu");

});

</SCRIPT>

<!-- 增删改查触发方法 -->

<!-- 增加触发方法   添加我是用button 触发的并没有使用右击的menu -->

<script type="text/javascript">

function toICAdd(){

window.location.href = "<c:url value='/ac/toAddAC.do'/>";

}

</script> 

<style type="text/css">

div#rMenu {position:absolutevisibility:hiddentop:0background-color#555;text-alignleft;padding2px;}

div#rMenu ul li{

margin1px 0;

padding0 5px;

cursorpointer;

list-stylenone outside none;

background-color#DFDFDF;

}

</style>

 </HEAD>

 

<BODY>

<div class="box-positon">

<div class="rpos">当前位置: 文章管理 - 分类</div>

<div class="clear"></div>

</div>

<h1>公告分类</h1>

 

 

 

<div class="content_wrap">

<div class="zTreeDemoBackground left">

<ul id="treeDemo" class="ztree"></ul>

</div>

</div>

 

<%--tool bar  --%>

<div class="tools">

<ul class="toolbar" >

<li onclick="toICAdd()" style="float: left">

<span><img src="<c:url value='/res/admin/images/t01.png'/>" />

</span>添加  

</li>

<li onclick="toSeeIC()" style="float: left">

   <span><img src="<c:url value='/res/admin/images/t04.png'/>" />

   </span>统计

</li>

</ul>

</div>   

<%--右击  tool bar --%> 

<div id="rMenu">

<ul>

<!--  <li id="m_add" onclick="addTreeNode();">Add Node</li>  -->

<li id="m_add" onclick="updateTreeNode();">Update Node</li>

<li id="m_del" onclick="removeTreeNode();">Delete Node</li>

<li id="m_check" onclick="checkTreeNode(true);">Check Node</li>

<li id="m_unCheck" onclick="checkTreeNode(false);">Uncheck Node</li>

<li id="m_reset" onclick="resetTree();">Resume zTree</li>

</ul>

</div>

</BODY>

 

以上为查询出的前台页面在看后台:

ACTION:查出List 以json格式传给页面,这是树的显示:

@Controller
public class ArticleClassAction {
    @Autowired
    private ArticleClassService service;
    @RequestMapping(value="/ac/getTree")
    public String getArticleClass(Model model) throws GenericBusinessException{
        List<ArticleClassBean> list = service.findAcList();
        JSONArray array =JSONArray.fromObject(list);
        String json = array.toString();
        
        json = json.replaceAll("acid", "id");     //将数据库里的字段,转换成 树需要的字段 ,进行了一下字段名的转换,树的显示需要id,pid(上级id),name.
        json = json.replaceAll("acfid", "pId");
        json = json.replaceAll("acname", "name");
        System.out.println("--------------------- json---------------"+json);
        model.addAttribute("json", json);
        System.out.println("--------------------model---------------"+model);
        return "/news/wenzhang/articleclass2";
    }


添加:

点击页面button,然后到添加页面,只需选择父级节点就可以实现添加,是最简单的,代码如下:

添加之前 需要把已有的分类都查出来,作为父类,供将要添加的子类选择

上面页面到的action代码为:

@RequestMapping(value="/ac/toAddAC")
    public String toAddAc(Model model){
        List<ArticleClassBean> list = service.findAcList();
        model.addAttribute("list",list);
        return "/news/wenzhang/addac";
    }
   

然后讲list  传到到页面:

<script type="text/javascript">
   
        function doAdd(){
            var acname=    document.getElementsByName("acname")[0].value;
            if(acname==null||acname==''){
                alert("不能为空!")
            return false;
            }else{
                document.forms[0].action="<c:url value='/ac/addAC.do'/>";
                document.forms[0].submit();
            }
            
        }
    </script>
        
        
        

    </head>
    <body>
    <div class="box-positon">
        <div class="rpos">当前位置: 文章管理 - 添加分类</div>
        <div class="clear"></div>
    </div>
      <form action="" method="post">
    <div class="formbody">
            <div class="formtitle">
                <span>文章分类</span>
            </div>
            <ul class="forminfo">
                <li>
                    <label>分类名称</label>
                    <input name="acname" type="text" class="dfinput" />
                </li>
                <li>
                    <label>上级名称</label>
                    <div class="vocation">
                    <select name="acid" class="select1">
                        <c:forEach items="${list}" var="list">
                            <option value="${list.acid}">${list.acname}</option>
                        </c:forEach>
                    </select>
                    </div>
                </li>
                <li>
                    <label>&nbsp;</label>
                    <input onclick="doAdd()" type="button" class="btn" value="确认添加"/>
                </li>
            </ul>
        </div>
    </form>   
        
        
    </body>
    </html>


然后再到ACTION执行 添加 ,这里就需要引出文章的亮点了

需要说明的是这里的acurl.

/**
     * DO ADD
     * 前台acid 是 分类父id
     * @param acname
     * @param acid
     * @return
     * @throws GenericBusinessException
     */
    @RequestMapping(value="/ac/addAC")
    public String doadd(String acname, Integer acid) throws GenericBusinessException{
        ArticleClassBean Fbean=service.getFbeanByAcid(acid);
        String Facurl=Fbean.getAcurl();
        String acurl=Facurl+"-"+acid;
        ArticleClassBean ac=new ArticleClassBean();
        ac.setAcfid(acid);
        ac.setAcname(acname);
        ac.setAcurl(acurl);
        service.save(ac);
        return "redirect:/ac/getTree.do";
    }



这个acurl是我为删除提供的一个数据库字段。可以把它当做一个标示码,这个码的规律是当前节点的所有上级节点id,组成。

目的是为了实现都层级关系时删除中间节点,级联删除他下面的所有节点,一般情况删除最后节点是最容易的,

删除倒数第二个节点也比较简单,如果层级关系超过三层,需要进行复杂判断了。

如图有七层,如当删除增加2时需要删出3,4.5.



节点1

     节点2

          节点3

              节点4

如果每个节点都配一个code,即我代码里的acurl

节点1的当前节点code为 0-1  (0根节点id,1为当前id,  -  为间隔,用字符串拼接可以实现)

节点2当前节点code为 0-1 -2 (0根节点id,1节点1 的id,2为当前节点id)

类推。。。

事实上我插入数据库的并不是当前节点code,而是上级节点code,

目的是新增节点时是无法获取新节点的id,导致当前节点code的最后一位无法实现拼接

所以存入的是上级的父节点code,这个是可以通过添加时的父节点id ,从数据库查出。

也就是上面代码的拼接,

然后删除就变得简单了,用的是模糊删除。

如删除节点2   code 码为上级code, 实际节点code即0-1  

需要拼接  上  当前节点的id -2    然后+% 模糊删除    节点2的子节点

还需一步删除节点2 ,代码如下 一目了然

如果删除的节点没有子节点 ,在页面时有一个判断,会调用另一个方法直接通过id删除 代码如下:

/**
     * 删除    如果有子节点  当前节点用id删除,而子节点用 code原理删除
     * @param model
     * @param request
     * @param ncid
     * @return
     */
    @RequestMapping(value="/ac/delFac")
    public String delCK(Model model,HttpServletRequest request,Integer acid){
        ArticleClassBean Fbean=service.getFbeanByAcid(acid);
        String code=Fbean.getAcurl();
        String acurl=code+"-"+acid;
        service.delFac(acid);
        service.delZincByAcurl(acurl);
        return "redirect:/ac/getTree.do";
    }
    
    /**
     * 删除子节点   树分支的最后节点
     * @param model
     * @param request
     * @param ncid
     * @return
     */
    @RequestMapping(value="/ac/delFac2")
    public String delCK2(Model model,HttpServletRequest request,Integer acid){
        service.delFac(acid);
        return "redirect:/ac/getTree.do";
    }
    
    
    
    @RequestMapping(value="/ac/updateFac")
    public String update(Model model,Integer acid){
        ArticleClassBean Fbean=service.getFbeanByAcid(acid);
        List<ArticleClassBean> list = service.findAcList();
        model.addAttribute("list",list);
        model.addAttribute("Fbean",Fbean);
        return "/news/wenzhang/updateac";
    }
    /**
     * 前台取到Bean的 父id即ncfid,
     * 然后通过ncfid作为id查出父类的Bean ,得到父类的code
     * 父类的code + 父类的id =  本bean的Code 即 ncurl字段
     * @param ncBean
     * @return
     */
    @RequestMapping(value="/ac/doUpdate")
    public String doupdate(ArticleClassBean acBean){
        Integer acfid=acBean.getAcfid();
        System.out.println("++++++++++++++父id+++++++++++++++==="+acfid);
        ArticleClassBean Fbean=service.getFbeanByAcid(acfid);
        String facurl=Fbean.getAcurl();
        System.out.println("++++++++++++++++父类的ncurl code+++++++++++++==="+facurl);
        String acurl=facurl+"-"+acfid;
        System.out.println("+++++++++++本类的+++++++++code+++++++++==="+acurl);
        acBean.setAcurl(acurl);
        System.out.println(acBean);
        service.save(acBean);
        return "redirect:/ac/getTree.do";
    }
    
   
数据库操作:


hql语句

@Service
public class ArticleClassServiceImpl extends BaseServiceImpl<ArticleClassBean>implements ArticleClassService {
    
    
    @Autowired
    private BaseDao<ArticleClassBean> dao;
    
    public List<ArticleClassBean> findAcList(){
        
            String hql="from  ArticleClassBean";
        try {
            return dao.find(hql);
        } catch (GenericBusinessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
        
    }

    @Override
    public PageModel<ArticleClassBean> findByPage(ArticleClassBean entity,
            Integer pageNo, Integer pageSize) throws GenericBusinessException {
        // TODO Auto-generated method stub
        return null;
    }
    
    
    public void save(ArticleClassBean ac){
        
        try {
            dao.saveOrUpdate(ac);
        } catch (GenericBusinessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    public ArticleClassBean getFbeanByAcid(Integer acid){
        String hql="From ArticleClassBean where acid="+acid;
        try {
            return (ArticleClassBean) dao.find(hql).get(0);
        } catch (GenericBusinessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    
    }
    public void delFac(Integer acid){
        String hql="delete from ArticleClassBean where acid="+acid+" or acfid="+acid+"";
         System.out.println(hql);
         try {
            dao.executeHql(hql);
        } catch (GenericBusinessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    public void delZincByAcurl(String acurl){
        String hql="delete from ArticleClassBean where acurl like '"+acurl+"%'";
        try {
            dao.executeHql(hql);
        } catch (GenericBusinessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
   

    }



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值