jQuery EasyUI 扩展 – 树形网格行拖放(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

引言:为什么需要树形网格的拖放功能?

在现代 Web 应用开发中,数据展示的直观性和交互性是提升用户体验的核心要素。树形网格(TreeGrid)作为 jQuery EasyUI 的核心组件之一,完美融合了树形结构与表格数据的特性,常用于组织层级数据(如部门架构、文件系统、分类目录等)。然而,当需要动态调整数据节点的位置或层级关系时,传统的点击操作显得不够直观。此时,树形网格行拖放功能便能发挥其独特优势,通过模拟现实世界中“拖拽物品”的操作逻辑,让用户以更自然的方式管理数据。

本篇将从零开始,逐步讲解如何为 EasyUI 的 TreeGrid 添加行拖放功能,并通过实际案例演示其核心实现逻辑。即使你是编程新手,也能通过本文掌握这一进阶技巧。


核心概念解析:理解树形网格与拖放机制

1. 什么是树形网格(TreeGrid)?

树形网格是表格(Grid)与树形结构(Tree)的结合体,兼具两者特性:

  • 表格属性:可展示多列数据,支持排序、分页、过滤等操作;
  • 树形属性:通过缩进和展开/折叠图标,展示父子层级关系。

例如,一个企业组织架构的 TreeGrid 可能包含以下字段: | 列名 | 数据类型 | 说明 | |---------------|----------|--------------------------| | 部门名称 | String | 部门的名称 | | 部门编号 | Integer | 唯一标识符 | | 上级部门 | Integer | 父节点ID | | 员工数量 | Integer | 该部门直接下属员工数量 |

2. 拖放操作的核心逻辑

拖放(Drag and Drop)的实现涉及三个关键步骤:

  1. 元素选中:用户通过鼠标点击或触摸选中目标节点;
  2. 位置跟踪:在拖动过程中实时更新元素位置;
  3. 数据更新:将最终位置映射到数据模型并持久化。

在 TreeGrid 中,拖放需要额外处理层级关系的变更,例如:

  • 当拖动一个子节点到另一父节点下时,需更新其 parentId 字段;
  • 需要验证拖放目标是否允许接收(如禁止跨层级移动)。

实现步骤:从配置到功能扩展

1. 基础环境搭建

(1)引入依赖库

在 HTML 文件中引入以下资源:

<link rel="stylesheet" href="https://www.jeasyui.com/easyui/themes/default/easyui.css">
<link rel="stylesheet" href="https://www.jeasyui.com/easyui/themes/icon.css">
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>

(2)创建基本 TreeGrid

<table id="deptTreeGrid" class="easyui-treegrid" 
       data-options="
           url: 'data.json',
           idField: 'id',
           treeField: 'name',
           rownumbers: true,
           animate: true,
           fitColumns: true,
           striped: true,
           onBeforeDrop: onBeforeDrop,
           onDrop: onDrop
       ">
    <thead>
        <tr>
            <th data-options="field:'name', width:150">部门名称</th>
            <th data-options="field:'id', width:80">部门编号</th>
            <th data-options="field:'parent', width:120">上级部门</th>
            <th data-options="field:'staffCount', width:100">员工数量</th>
        </tr>
    </thead>
</table>

2. 启用拖放功能

(1)配置拖放选项

在 TreeGrid 的 data-options 中添加以下参数:

draggable: {
    enable: true,
    handle: '.drag-handler' // 拖拽触发区域(可选)
},
dropable: {
    enable: true,
    onBeforeDrop: onBeforeDrop,
    onDrop: onDrop
}

(2)实现拖放事件处理函数

function onBeforeDrop(targetNode, sourceNode) {
    // 验证拖放合法性(例如:不能拖到自身后代节点)
    if (isDescendant(targetNode, sourceNode)) {
        $.messager.alert('提示', '不能拖拽到后代节点');
        return false;
    }
    return true;
}

function onDrop(targetNode, sourceNode) {
    // 更新数据模型(此处需根据业务逻辑编写)
    updateParentId(sourceNode.id, targetNode.id);
}

核心逻辑详解:拖放事件与数据更新

1. 层级关系验证

onBeforeDrop 中,我们需要确保拖放操作符合业务规则。例如,禁止将父节点拖到子节点之下:

function isDescendant(parent, child) {
    while (child) {
        if (child.id === parent.id) return true;
        child = child.parent;
    }
    return false;
}

2. 数据持久化

onDrop 的核心是将新父节点ID写入数据库。此处以 AJAX 示例:

function updateParentId(childId, newParentId) {
    $.ajax({
        url: '/api/updateParent',
        type: 'POST',
        data: { childId, newParentId },
        success: function(response) {
            if (response.success) {
                // 刷新 TreeGrid 数据
                $('#deptTreeGrid').treegrid('reload');
            }
        }
    });
}

实战案例:部门结构调整系统

1. 案例场景

某公司进行组织架构调整,需允许管理员通过拖放:

  • 将“市场部”从“总部”下级拖到“华东分公司”;
  • 调整“技术部”下属的“前端组”到“后端组”之下。

2. 完整代码实现

<!-- HTML结构 -->
<div style="width:800px;">
    <table id="orgTreeGrid"></table>
</div>

<script>
$(function() {
    $('#orgTreeGrid').treegrid({
        url: '/api/departments',
        idField: 'id',
        treeField: 'name',
        columns: [[
            { field: 'name', title: '部门名称', width: 200 },
            { field: 'parentId', title: '上级部门ID', width: 120 },
            { field: 'staffCount', title: '员工数', width: 80 }
        ]],
        // 启用拖放
        draggable: {
            enable: true,
            revert: true // 拖放失败时复位
        },
        droppable: {
            enable: true,
            onBeforeDrop: function(targetNode, sourceNode) {
                // 禁止跨层级拖动
                if (sourceNode.level - targetNode.level > 1) {
                    return false;
                }
                return true;
            },
            onDrop: function(targetNode, sourceNode) {
                // 更新父子关系
                let newParentId = targetNode.id;
                updateHierarchy(sourceNode.id, newParentId);
            }
        }
    });
});

// 更新数据库
function updateHierarchy(childId, newParentId) {
    // 实现逻辑与前文类似
}
</script>

进阶技巧:优化用户体验

1. 可视化反馈

通过 CSS 实现拖拽时的视觉提示:

.treegrid-dnd-proxy {
    border: 2px dashed #00f;
    background-color: #ddf;
    opacity: 0.8;
}

2. 多级拖放限制

onBeforeDrop: function(targetNode, sourceNode) {
    // 限制最多三层嵌套
    if (targetNode.level + 1 > 3) return false;
    // 禁止将父节点拖到子节点之下
    if (isAncestor(sourceNode, targetNode)) return false;
    return true;
}

3. 错误处理

$(document).on('dragstop', '.treegrid-row', function(e) {
    if (e.data.error) {
        $.messager.alert('警告', '拖拽目标不可用');
    }
});

常见问题与解决方案

1. 节点拖放后位置未更新

原因:未调用 treegrid('reload') 刷新数据
解决:在 onDrop 后强制刷新:

$('#orgTreeGrid').treegrid('reload');

2. 跨浏览器兼容问题

建议

  • 使用 jQuery UI 的拖放插件作为补充
  • 对 IE 浏览器添加特殊兼容处理

3. 性能优化

  • 对大数据量启用虚拟滚动(Virtual Scrolling)
  • onBeforeDrop 中预先过滤非法目标节点

结语:构建动态交互的新可能

通过本文的讲解,我们完成了从基础概念到实战案例的完整学习路径。jQuery EasyUI 的树形网格行拖放功能,不仅简化了复杂数据结构的管理流程,更通过直观的交互设计提升了用户参与感。随着 Web 应用对交互体验的要求越来越高,掌握这类增强型组件的使用,将成为开发者提升项目竞争力的关键技能。

在后续实践中,你可以进一步探索以下方向:

  • 结合表单验证实现拖放时的参数校验
  • 实现跨 TreeGrid 的节点拖放
  • 将拖放操作与版本控制结合,记录数据变更历史

通过不断实践与优化,你将能打造出让用户真正“爱不释手”的动态界面。

最新发布