LayUI Tree 组件实战:从数据渲染到增删改查完整指南

作者:工具松鼠

时间:2026-10-25

浏览:166

本文详细解析 LayUI Tree 组件的实际应用,涵盖从引入样式、配置参数到后台数据交互的全过程。重点讲解如何通过递归处理 JSON 键名映射,实现树形数据的正确渲染。同时深入演示节点点击、编辑、删除及新增操作的回调处理,并结合 LayUI TreeSelect 实现上级部门选择,最后提供获取选中节点并转换为 JSON 字符串传给后台的完整解决方案。

文章目录

树形结构在软件开发中应用广泛,例如部门组织架构管理、系统权限菜单配置等场景。采用树形结构展示层级关系,能够使界面逻辑更加清晰直观,便于用户理解和管理。

在近期开发的一个个人博客项目中,笔者使用了 LayUI 的树形组件,并基于此构建了一个小型案例。现将该案例的开发过程与核心代码整理分享,供参考。

先看一下显示的效果图

先看一下显示的效果图

点击树节点右侧的操作图标,可展开对应部门的详细信息并进行编辑。系统支持自定义按钮以添加部门,同时也内置了标准的新增、修改和删除功能。此外,程序支持获取当前选中的节点数据,以便根据具体业务需求(如选中后自动保存)进行后续处理。

使用前,首先需要在项目中引入 LayUI 框架所需的 JavaScript 和 CSS 样式文件,确保组件正常加载。

案例对应的实体类Dept

@Entity
public class Dept {
    private Integer id;
    private String name;    //部门名称
    private String deptName;    //部门负责人
    private String phone;   //电话号
    private String number;  //编号
    private double idx;     //排序
    @JsonIgnore
    private Dept parent;
    @JsonIgnore
    private List<Dept> children = new ArrayList<>();
 
    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getDeptName() {
        return deptName;
    }
 
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
 
    public String getPhone() {
        return phone;
    }
 
    public void setPhone(String phone) {
        this.phone = phone;
    }
 
    public String getNumber() {
        return number;
    }
 
    public void setNumber(String number) {
        this.number = number;
    }
 
    public double getIdx() {
        return idx;
    }
 
    public void setIdx(double idx) {
        this.idx = idx;
    }
 
    @ManyToOne
    @CreatedBy
    public Dept getParent() {
        return parent;
    }
 
    public void setParent(Dept parent) {
        this.parent = parent;
    }
 
    @OneToMany(cascade=CascadeType.ALL,mappedBy="parent")
    @OrderBy(value="idx")
    public List<Dept> getChildren() {
        return children;
    }
 
    public void setChildren(List<Dept> children) {
        this.children = children;
    }
 
    public Dept(Integer id, String name, String deptName, String phone, String number, double idx, Dept parent, List<Dept> children) {
        this.id = id;
        this.name = name;
        this.deptName = deptName;
        this.phone = phone;
        this.number = number;
        this.idx = idx;
        this.parent = parent;
        this.children = children;
    }
 
    public Dept(Integer id) {
        this.id = id;
    }
 
    public Dept() {
    }
}

在 LayUI 中渲染树形菜单,前端仅需提供一个指定的标签容器即可,无需复杂的 DOM 结构。

<div id="dept_tree">
</div>

除了基础的树形展示,案例中还包含了其他辅助 UI 元素,例如右侧用于显示详情信息的区域、用于触发新增操作的按钮等,以完善用户体验。

完整代码如下

<style type="text/css">
    #dept_main, #dept_particulars{
        width: 48.5%;
        display: inline-block;
        vertical-align: top;
        padding: 20px;
        background: white;
        box-sizing: border-box;
    }
    #dept_tree{
        margin-top: 20px;
    }
</style>
<div id="dept_main" style="margin-right: 2%;">
    <fieldset class="layui-elem-field layui-field-title">
        <legend>所有部门</legend>
    </fieldset>
    <button class="layui-btn layui-btn-sm layui-btn-radius layui-btn-normal" lay-demo="addDept"><i class="layui-icon">&#xe654;</i>添加部门</button>
    <button class="layui-btn layui-btn-sm layui-btn-radius layui-btn-normal" lay-demo="gain">获取选中节点</button>
    <div id="dept_tree">
 
    </div>
</div>
<div id="dept_particulars">
    <fieldset class="layui-elem-field layui-field-title">
        <legend>部门详情</legend>
    </fieldset>
    <div id="dept_home">
        <div class="layui-tree-emptyText">无数据</div>
    </div>
</div>

前端通过 JavaScript 请求后端数据并渲染页面。data 变量用于存储请求到的数据源。起初尝试直接传入请求链接,但发现无法正常工作,因此改为封装一个专门的方法来获取数据源。

layui.use(['tree', 'util'], function() {
    var tree = layui.tree;
    var util = layui.util;
    tree.render({
        elem: '#dept_tree',
        data: getData(),
        id: 'treeId',
        showCheckbox: true,     //是否显示复选框
        onlyIconControl: true
    });
});
 
function getData(){
    var data = [];
    $.ajax({
        url: "dept/treeload",    //后台数据请求地址
        type: "post",
        async:false,
        success: function(resut){
            data = resut;
        }
    });
    return data;
}

tree 组件提供了丰富的基础配置参数,开发者可根据具体业务需求进行相应设置。

参数选项说明类型示例值
elem指向容器选择器String/Object-
data数据源Array-
id设定实例唯一索引,用于基础方法传参使用。String-
showCheckbox是否显示复选框Booleanfalse
edit是否开启节点的操作图标。默认 false。
  • 若为 true,则默认显示“改删”图标
  • 若为 数组,则可自由配置操作图标的显示状态和顺序,目前支持的操作图标有:add、update、del,如:edit: ['add', 'update', 'del']
Boolean/Array['update', 'del']
accordion是否开启手风琴模式,默认 falseBooleanfalse
onlyIconControl是否仅允许节点左侧图标控制展开收缩。默认 false(即点击节点本身也可控制)。若为 true,则只能通过节点左侧图标来展开收缩Booleanfalse
isJump是否允许点击节点时弹出新窗口跳转。默认 false,若开启,需在节点数据中设定 link 参数(值为 url 格式)Booleanfalse
showLine是否开启连接线。默认 true,若设为 false,则节点左侧出现三角图标。Booleantrue
text自定义各类默认文本,目前支持以下设定:

text: {

defaultNodeName: '未命名' //节点默认名称

,none: '无数据' //数据为空时的提示文本

}

Object-

由于 LayUI tree 组件指定了 JSON 数据中特定字段的键名,若后台返回的数据键名与组件要求不一致,则需要进行映射处理。另一种方案是让实体类的属性名直接对应 tree 所需的 JSON 键名,以简化处理流程。

组件要求的 JSON 数据键名定义如下:

属性选项说明类型示例值
title节点标题String未命名
id节点唯一索引,用于对指定节点进行各类操作String/Number任意唯一的字符或数字
children子节点。支持设定选项同父节点Array[{title: '子节点1', id: '111'}]
href点击节点弹出新窗口对应的 url。需开启 isJump 参数String任意 URL
spread节点是否初始展开,默认 falseBooleantrue
checked节点是否初始为选中状态(如果开启复选框的话),默认 falseBooleantrue
disabled节点是否为禁用状态。默认 falseBooleanfalse

以下是后端负责提供数据的方法实现。

@RequestMapping(value = "/treeload")
@ResponseBody
public Object treeload(){
    Sort sort = Sort.by("idx");
    List<Dept> dpet = deptService.findByParentIsNull(sort);    //查找所有菜单
    List<HashMap<String, Object>> result = new ArrayList<>();    //定义一个map处理json键名问题
    return fun(dpet, result);
}
 
private Object fun(List<Dept> dpet, List<HashMap<String, Object>> result) {
    for(Dept d : dpet){
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", d.getId());
        map.put("title", d.getName());
        map.put("spread", true);      //设置是否展开
        List<HashMap<String, Object>> result1 = new ArrayList<>();
        List<Dept> children = d.getChildren();    //下级菜单
        //这里可以根据自己需求判断节点默认选中
        /*if(m.getParent() != null || m.getChildren().size() == 0){
            map.put("checked", true);    //设置为选中状态
        }*/
        map.put("children", fun(children, result1));
        result.add(map);
    }
    return result;
}

由于本案例中新建的实体类字段名与 tree 组件指定的 JSON 键名不一致,因此使用了一个名为 fun 的递归方法进行处理。在递归过程中,可根据项目实际需求,通过条件判断来决定是否选中特定节点。

后端返回的 JSON 数据格式需符合 LayUI tree 组件的要求。

先看一下显示的效果图

[
	{
		"children": [		//子节点
			{
				"children": [
					{
						"children": [],
						"id": 30,
						"title": "测试",
						"spread": true
					}, {
						"children": [],
						"id": 31,
						"title": "开发",
						"spread": true
					}, {
						"children": [
							{
								"children": [],
								"id": 36,
								"title": "测试节点",
								"spread": true
							}
						],
						"id": 32,
						"title": "测试",
						"spread": true
					}
				],
				"id": 2,
				"title": "技术部",
				"spread": true
			}, {
				"children": [],
				"id": 19,
				"title": "财务部",
				"spread": true
			}
		],
		"id": 1,	//节点id
		"title": "某某公司",	//节点名称
		"spread": true
	}, {
		"children": [],
		"id": 33,
		"title": "测试",
		"spread": true
	}
]

设置节点点击事件的回调方法,该代码需添加到加载数据的 tree.render 配置中。

click: function (obj) {
    var id = obj.data.id;
    $("#dept_home").load("dept/show?id="+id);
}

当点击节点时,将请求到的详情页面内容加载到右侧的 div 容器中显示。此处涉及后端的数据查询方法。

@RequestMapping(value = "/show")
public void show(DeptForm form, ModelMap map) throws InstantiationException, IllegalAccessException {
    Dept model = new Dept();
    Integer id = form.getId();
    Integer parentId = 0;
    if(id!=null) {
        model = deptService.findById(id);
        parentId = model.getParent()==null?0:model.getParent().getId();
    }
    map.put("parentId", parentId);
    map.put("model", model);
}

DeptForm 类作为一个接收类,其字段定义与实体类保持一致。系统根据请求传递过来的 id,查询该条数据的详细信息,随后将当前部门的详情数据及父级节点 id(用于在下拉树 TreeSelect 中显示上级部门)传递给详情页面。

以下是 show.html 详情页面的完整代码实现。

<meta charset="UTF-8" />
<style type="text/css">
    .myData .layui-form-item{
        margin: 20px 100px 10px 45px;
    }
    .myData .layui-form-label{
        width: 85px;
    }
    .layui-input-block {
        margin-left: 120px;
    }
</style>
<form class="layui-form myData" action="save" method="post" lay-filter="stuform">
    <input type="hidden" name="id" data-th-value="${model.id}" />
 
    <div class="layui-form-item">
        <label class="layui-form-label">上级部门:</label>
        <div class="layui-input-block">
            <input type="text" name="parentId" id="tree" lay-filter="tree" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">部门名称:</label>
        <div class="layui-input-block">
            <input type="text" name="name" lay-verify="required" th:value="${model.name}" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">部门负责人:</label>
        <div class="layui-input-block">
            <input type="text" name="deptName" th:value="${model.deptName}" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">电话:</label>
        <div class="layui-input-block">
            <input type="text" name="phone" th:value="${model.phone}" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">编号:</label>
        <div class="layui-input-block">
            <input type="text" name="number" th:value="${model.number}" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">排序:</label>
        <div class="layui-input-block">
            <input type="text" name="idx" value="0" th:value="${model.idx}" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label"></label>
        <div class="layui-input-block">
            <button lay-submit class="layui-btn layui-btn-radius layui-btn-normal" lay-filter="btnSub">
                <i class="layui-icon">&#xe642;</i>修改并保存
            </button>
        </div>
    </div>
</form>
 
<script th:inline="javascript">
    layui.use(["treeSelect", "form", "tree"], function () {
        var form = layui.form;
        var tree = layui.tree;
        form.render('select');
        var treeSelect = layui.treeSelect;
        treeSelect.render({
            // 选择器
            elem: '#tree',
            // 数据
            data: 'dept/treeSelect?id='+[[${model.id==null ? 0 : model.id}]],
            // 异步加载方式:get/post,默认get
            type: 'post',
            // 占位符
            placeholder: '上级菜单',
            // 是否开启搜索功能:true/false,默认false
            search: true,
            // 一些可定制的样式
            style: {
                folder: {
                    enable: true
                },
                line: {
                    enable: true
                }
            },
            // 加载完成后的回调函数
            success: function (d) {
                // 选中节点,根据id筛选
                treeSelect.checkNode('tree', [[${model.parent == null? parentId: model.parent.id}]]);
                treeSelect.refresh('tree');
            }
        });
 
        form.on('submit(btnSub)', function (data) {
            $.post('dept/save', data.field, function (result) {
                if (result.success) {
                    tree.reload('treeId', {data: getData()});
                }
                layer.msg(result.msg, {offset: 'rb'});
            });
            return false;
        });
    });
</script>

上级部门的选择使用了 LayUI 的下拉树组件(TreeSelect)。关于下拉树的数据请求方法,可参考 LayUI 下拉树 TreeSelect 的使用文档。

@RequestMapping(value="/treeSelect")
@ResponseBody
public Object treeSelect(Integer id) {
    Sort sort = Sort.by("idx");
    Specification<Dept> spec = buildSpec1();
    List<Dept> list = deptService.findAll(spec,sort);
    return buildTree(list, id);
}
 
private Object buildTree(List<Dept> list, Integer id) {
    List<HashMap<String, Object>> result=new ArrayList<>();
    for (Dept dept : list) {
        if(dept.getId() != id) {
            HashMap<String, Object> node=new HashMap<>();
            node.put("id", dept.getId());
            node.put("name",dept.getName());
            node.put("open", false);
            node.put("checked", false);
            if(dept.getChildren().size() != 0) {
                node.put("children",buildTree(dept.getChildren(), id));
            }
            result.add(node);
        }
    }
 
    return result;
}
 
public Specification<Dept> buildSpec1() {
    Specification<Dept> specification = new Specification<Dept>() {
 
        private static final long serialVersionUID = 1L;
 
        @Override
        public Predicate toPredicate(Root<Dept> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            HashSet<Predicate> rules=new HashSet<>();
            Predicate parent = cb.isNull(root.get("parent"));
            rules.add(parent);
            return cb.and(rules.toArray(new Predicate[rules.size()]));
        }
 
    };
    return specification;
}

上述配置最终呈现的界面效果如图所示。

先看一下显示的效果图

以下是修改并保存数据到后台的方法。由于新增和修改功能共用一个接口,系统通过 id 是否存在来区分操作类型。

@Override
public Object save(DeptForm form) {
    try {
        Dept model = new Dept();
        Integer id = form.getId();
        if(id != null) {
            model = deptService.findById(id);
        }
        //父级菜单id
        Integer parentId = form.getParentId();
        if(parentId == null) {
            model.setParent(null);
        }else {
            model.setParent(new Dept(parentId));
        }
        BeanUtils.copyProperties(form, model,"id", "parent");
        deptService.save(model);
        return new AjaxResult("数据保存成功!");
    } catch (Exception e) {
        return new AjaxResult(false,"数据保存失败");
    }
}

设置节点操作图标(如新增、修改、删除)的回调,该代码需添加到加载数据的 tree.render 配置中。

edit: ['add', 'update', 'del'], //操作节点的图标
operate: function(obj){
    var type = obj.type; //得到操作类型:add、edit、del
    var data = obj.data; //得到当前节点的数据
    var elem = obj.elem; //得到当前节点元素
 
    var id = data.id;
    var name = data.title;
    if(type === 'add'){ //增加节点
        $.post("dept/save", {parentId: id, name: "未命名"}, function (result) {
            tree.reload('treeId', {data: getData()});
        })
        //返回 key 值
        return ;
    } else if(type === 'update'){ //修改节点
        $.post("dept/update", {id: id, name: name}, function () {
            tree.reload('treeId', {data: getData()});
        })
    } else if(type === 'del'){ //删除节点
        $.post("dept/delete", {id: id}, function () {
            tree.reload('treeId', {data: getData()});
        });
    };
}

其中 operate 为操作节点时的回调方法,用于处理用户点击操作图标的行为。

obj.type 表示操作类型,包括 add(新增)、update(修改)和 del(删除)。obj.data 包含操作节点后的最新数据对象。

当执行新增节点操作后,前端向后台发送请求以添加该节点。save 方法与上述修改方法类似,区别在于传递的 id 为新建节点的父级节点 id。

执行修改节点操作时,前端同样向后台发送修改请求,并传递该对象的 id 以及修改后的数据作为参数。后端响应方法负责处理数据更新。

@RequestMapping(value = "/update")
@ResponseBody
public Object update(DeptForm form) {
    try {
        Dept model = deptService.findById(form.getId());
        model.setName(form.getName());
        deptService.save(model);
        return new AjaxResult("数据保存成功!");
    } catch (Exception e) {
        return new AjaxResult(false,"数据保存失败");
    }
}

删除节点的操作逻辑类似,前端只需传递被删除节点的 id 即可。后端提供对应的删除请求处理方法。

@RequestMapping(value="/delete")
@ResponseBody
public Object delete(Integer id) {
	try {
		deptService.deleteById(id);
		return new AjaxResult("数据删除成功");
	} catch (Exception e) {
		return new AjaxResult(false,"数据删除失败");
	}
}

除了节点自带的操作图标,还可以通过外部按钮来操作树形菜单。

在页面中定义两个按钮,分别为它们添加 lay-demo 属性并设置对应的属性值。前端 JavaScript 通过监听该属性值,绑定相应的点击事件。

<button class="layui-btn layui-btn-sm layui-btn-radius layui-btn-normal" lay-demo="addDept"><i class="layui-icon">&#xe654;</i>添加部门</button>
<button class="layui-btn layui-btn-sm layui-btn-radius layui-btn-normal" lay-demo="gain">获取选中节点</button>

以下是绑定“添加部门”和“获取选中节点”按钮点击事件的具体 JavaScript 代码。

util.event('lay-demo', {
    addDept: function(othis){
        $.get('dept/edit', function(data) {
            layer.open({
                type: 1,
                title: '新增',
                area: ['530px'],
                content: data,
                btn: ['提交', '退出'],
                yes: function () {
                },
                success: function (layero, index) {
                    layui.use('form', function () {
                        var form = layui.form;
                        layero.addClass('layui-form');
                        var submitBtn = layero.find('.layui-layer-btn0');
                        submitBtn.attr('lay-filter', 'formVerify').attr('lay-submit', '');
                        layero.keydown(function (e) {
                            if (e.keyCode == 13) {
                                submitBtn.click();
                            }
                        });
 
                        form.on('submit(formVerify)', function (data) {
                            $.post('dept/save', data.field, function (result) {
                                if (result.success) {
                                    layer.close(index);
                                    tree.reload('treeId', {data: getData()});
                                }
                                layer.msg(result.msg, {offset: 'rb'});
                            });
                            return false;
                        });
                    });
                }
            })
        })
    },
    gain: function () {
        var checkData = tree.getChecked('treeId');
        var str = JSON.stringify(checkData);
        $.post('dept/checkedGain', {data: str}, function () {
        });
        layer.alert(JSON.stringify(checkData), {shade:0});
    }
});

点击“添加部门”按钮时,前端先发送请求到后台,并跳转至 edit 新增页面。edit.html 新增页面的代码与之前的 show.html 显示部门详情页面类似。上级部门同样使用 LayUI 下拉树组件显示,其数据请求方法与详情页面中的下拉树请求方法一致。新增后的保存逻辑也与前述保存方法相同。关于 LayUI 下拉树 TreeSelect 的具体使用,可参考相关文档。

以下是后端接收请求并跳转至 edit 页面的方法代码。

@RequestMapping(value = "/edit")
public void edit(){
    
}

edit.html 页面的完整代码如下所示。

<meta charset="UTF-8" />
<style type="text/css">
    .myData .layui-form-item{
        margin: 20px 100px 10px 45px;
    }
    .myData .layui-form-label{
        width: 85px;
    }
    .layui-input-block {
        margin-left: 120px;
    }
</style>
<form class="layui-form myData" action="save" method="post" lay-filter="stuform">
 
    <div class="layui-form-item">
        <label class="layui-form-label">上级部门:</label>
        <div class="layui-input-block">
            <input type="text" name="parentId" id="tree2" lay-filter="tree2" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">部门名称:</label>
        <div class="layui-input-block">
            <input type="text" name="name" lay-verify="required" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">部门负责人:</label>
        <div class="layui-input-block">
            <input type="text" name="deptName" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">电话:</label>
        <div class="layui-input-block">
            <input type="text" name="phone" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">编号:</label>
        <div class="layui-input-block">
            <input type="text" name="number" class="layui-input" />
        </div>
    </div>
    <div class="layui-form-item" >
        <label class="layui-form-label">排序:</label>
        <div class="layui-input-block">
            <input type="text" name="idx" value="0" class="layui-input" />
        </div>
    </div>
</form>
 
<script th:inline="javascript">
    layui.use(["treeSelect", "form"], function () {
        var form = layui.form;
        form.render('select');
        var treeSelect = layui.treeSelect;
        treeSelect.render({
            // 选择器
            elem: '#tree2',
            // 数据
            data: 'dept/treeSelect',
            // 异步加载方式:get/post,默认get
            type: 'post',
            // 占位符
            placeholder: '上级菜单',
            // 是否开启搜索功能:true/false,默认false
            search: true,
            // 一些可定制的样式
            style: {
                folder: {
                    enable: true
                },
                line: {
                    enable: true
                }
            },
            // 加载完成后的回调函数
            success: function (d) {
            }
        });
    });
</script>

上述代码运行后的页面效果如图所示。

先看一下显示的效果图

点击“获取选中节点”按钮时,若项目要求保存数据,则需要获取选中节点的数据。此处可获取选中节点的数据,并将其作为参数传递到后台。传递到后台的数据是一个 JSON 字符串,需要进行转换处理。这里推荐两个常用的 JSON 转换工具:net.sf.json.JSONObject 和 Alibaba Fastjson。本案例使用的是 Alibaba Fastjson,需在项目中引入相应的依赖。

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.47</version>
</dependency>

为了便于输出和处理,新建了一个与 tree JSON 数据键名一致的工具类 DeptTree,具体代码如下。

import java.util.ArrayList;
import java.util.List;
 
public class DeptTree {
    private Integer id;
    private String title;
    private boolean checked;
    private boolean spread;
    private List<DeptTree> children = new ArrayList<>();
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public List<DeptTree> getChildren() {
        return children;
    }
 
    public void setChildren(List<DeptTree> children) {
        this.children = children;
    }
 
    public boolean isChecked() {
        return checked;
    }
 
    public void setChecked(boolean checked) {
        this.checked = checked;
    }
 
    public boolean isSpread() {
        return spread;
    }
 
    public void setSpread(boolean spread) {
        this.spread = spread;
    }
}

后端接收到前端传递过来的 JSON 数据字符串后,将其转换并输出结果。

@RequestMapping(value = "/checkedGain")
@ResponseBody
public void checkedGain(String data){
    List<DeptTree> array2 = JSONArray.parseArray(data, DeptTree.class);
    treeData(array2);
}
 
//递归输出选中数据
private void treeData(List<DeptTree> array2) {
    for (DeptTree tree: array2){
        System.out.println(tree.getTitle()+"==="+tree.getId());
        if(tree.getChildren() != null){
            treeData(tree.getChildren());
        }
    }
}

选中节点后,点击“获取选中节点数据”按钮,前端将选中数据发送至后台。

先看一下显示的效果图

后端对应方法接收数据,进行转换后输出处理结果。

先看一下显示的效果图

获取到数据后,后续的保存逻辑便变得简单直接。

后端相关方法的代码已在上述部分展示,页面全部代码如下。

<style type="text/css">
    #dept_main, #dept_particulars{
        width: 48.5%;
        display: inline-block;
        vertical-align: top;
        padding: 20px;
        background: white;
        box-sizing: border-box;
    }
    #dept_tree{
        margin-top: 20px;
    }
</style>
 
<div id="dept_main" style="margin-right: 2%;">
    <fieldset class="layui-elem-field layui-field-title">
        <legend>所有部门</legend>
    </fieldset>
    <button class="layui-btn layui-btn-sm layui-btn-radius layui-btn-normal" lay-demo="addDept"><i class="layui-icon">&#xe654;</i>添加部门</button>
    <button class="layui-btn layui-btn-sm layui-btn-radius layui-btn-normal" lay-demo="gain">获取选中节点</button>
    <div id="dept_tree">
 
    </div>
</div>
<div id="dept_particulars">
    <fieldset class="layui-elem-field layui-field-title">
        <legend>部门详情</legend>
    </fieldset>
    <div id="dept_home">
        <div class="layui-tree-emptyText">无数据</div>
    </div>
</div>
 
<script type="text/javascript">
    layui.use(['tree', 'util', 'layer'], function() {
        var tree = layui.tree;
        var util = layui.util;
        var layer = layui.layer;
        tree.render({
            elem: '#dept_tree',
            data: getData(),
            id: 'treeId',
            showCheckbox: true,     //时候显示复选框
            onlyIconControl: true,
            edit: ['add', 'update', 'del'], //操作节点的图标
            click: function (obj) {
                var id = obj.data.id;
                $("#dept_home").load("dept/show?id="+id);
            },
            operate: function(obj){
                var type = obj.type; //得到操作类型:add、edit、del
                var data = obj.data; //得到当前节点的数据
                var elem = obj.elem; //得到当前节点元素
 
                var id = data.id;
                var name = data.title;
                if(type === 'add'){ //增加节点
                    $.post("dept/save", {parentId: id, name: "未命名"}, function (result) {
                        tree.reload('treeId', {data: getData()});
                    })
                    //返回 key 值
                    return ;
                } else if(type === 'update'){ //修改节点
                    $.post("dept/update", {id: id, name: name}, function () {
                        tree.reload('treeId', {data: getData()});
                    })
                } else if(type === 'del'){ //删除节点
                    $.post("dept/delete", {id: id}, function () {
                        tree.reload('treeId', {data: getData()});
                    });
                };
            }
        });
 
        util.event('lay-demo', {
            addDept: function(othis){
                $.get('dept/edit', function(data) {
                    layer.open({
                        type: 1,
                        title: '新增',
                        area: ['530px'],
                        content: data,
                        btn: ['提交', '退出'],
                        yes: function () {
                        },
                        success: function (layero, index) {
                            layui.use('form', function () {
                                var form = layui.form;
                                layero.addClass('layui-form');
                                var submitBtn = layero.find('.layui-layer-btn0');
                                submitBtn.attr('lay-filter', 'formVerify').attr('lay-submit', '');
                                layero.keydown(function (e) {
                                    if (e.keyCode == 13) {
                                        submitBtn.click();
                                    }
                                });
 
                                form.on('submit(formVerify)', function (data) {
                                    $.post('dept/save', data.field, function (result) {
                                        if (result.success) {
                                            layer.close(index);
                                            tree.reload('treeId', {data: getData()});
                                        }
                                        layer.msg(result.msg, {offset: 'rb'});
                                    });
                                    return false;
                                });
                            });
                        }
                    })
                })
            },
            gain: function () {
                var checkData = tree.getChecked('treeId');
                var str = JSON.stringify(checkData);
                $.post('dept/checkedGain', {data: str}, function () {
                });
                layer.alert(JSON.stringify(checkData), {shade:0});
            }
        });
    });
 
    function getData(){
        var data = [];
        $.ajax({
            url: "dept/treeload",    //后台数据请求地址
            type: "post",
            async:false,
            success: function(resut){
                data = resut;
            }
        });
        return data;
    }
    
</script>

以上为个人开发经验的总结,希望能为大家提供有益的参考。也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章