下面直接给你最实用、最常见的树形菜单加载父/子节点方法(也叫懒加载父子节点树),jQuery EasyUI 的 tree 组件完美支持这种模式:先加载顶级(父)节点,点击某个父节点时再异步加载它的直接子节点(不加载孙子节点,直到点击孙子节点的父节点),复制粘贴就能用,超级适合部门组织架构、菜单管理、无限级商品分类等场景,领导最爱的“性能好、加载快”效果全都有!
方法1:最推荐 – 标准父/子节点懒加载树(现在就用这个,3秒出效果)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EasyUI 树形菜单 - 加载父/子节点(懒加载)</title>
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/icon.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
</head>
<body>
<div style="margin:30px;width:300px;">
<p><strong>部门组织架构(点击部门加载下级)</strong></p>
<!-- 关键:只设置根节点url,不用onBeforeExpand -->
<ul id="deptTree" class="easyui-tree" data-options="
url:'get_parent_nodes.php', <!-- 只加载顶级父节点 -->
method:'get',
animate:true,
lines:true,
loadFilter: myLoadFilter <!-- 可选:统一处理返回数据 -->
"></ul>
</div>
<script>
// 核心:当点击有子节点的节点时,自动向同一个url请求子节点(EasyUI内置机制)
$('#deptTree').tree({
// 当节点展开前,如果子节点未加载,会自动向url发送 parentId 参数请求子节点
// 无需手动写onBeforeExpand!
onLoadSuccess: function(node, data){
// data是当前加载的节点数据
console.log('加载完成:', node ? node.text : '根节点');
},
onClick: function(node){
$.messager.show({
title:'你点击了',
msg:'部门:' + node.text + (node.children ? '(已加载子节点)' : ''),
timeout:2000
});
}
});
// 可选:统一处理后台返回数据格式
function myLoadFilter(data, parent){
// EasyUI默认期望 [{id,text,state,children:[]}, ...]
// 如果你的后台返回 {id,name,hasChild:true} 可以在这里转换
var result = [];
$.each(data, function(i, item){
var node = {
id: item.id,
text: item.name || item.text,
iconCls: item.icon
};
// 关键:如果有子节点,设置state:'closed',EasyUI会自动懒加载
if(item.hasChild || item.childrenCount > 0){
node.state = 'closed';
}
result.push(node);
});
return result;
}
</script>
</body>
</html>
后台接口示例(get_parent_nodes.php)
EasyUI 会自动在加载子节点时传 id 参数(选中节点的id)
<?php
// 获取父节点ID(根节点时没有)
$parentId = isset($_GET['id']) ? intval($_GET['id']) : 0;
// 模拟数据(实际从数据库查该父节点下的直接子节点)
$nodes = [];
if($parentId == 0){
// 加载顶级部门
$nodes = [
['id'=>1, 'name'=>'总公司', 'hasChild'=>true],
['id'=>2, 'name'=>'子公司A', 'hasChild'=>true]
];
} elseif($parentId == 1){
// 总公司下的部门
$nodes = [
['id'=>11, 'name'=>'技术部', 'hasChild'=>true],
['id'=>12, 'name'=>'市场部', 'hasChild'=>false],
['id'=>13, 'name'=>'财务部', 'hasChild'=>true]
];
} elseif($parentId == 11){
// 技术部下的小组
$nodes = [
['id'=>111, 'name'=>'前端组'],
['id'=>112, 'name'=>'后端组'],
['id'=>113, 'name'=>'测试组']
];
}
// ... 其他分支
echo json_encode($nodes);
?>
效果亮点:
- 页面打开只加载顶级节点(速度极快)
- 点击有子节点的部门 → 自动请求该部门下的直接子部门(不会一次性加载所有孙子、重孙子)
- 再次点击已加载的节点 → 直接展开/折叠(不再重复请求)
- 完美支持无限级层级(10级都没问题)
- EasyUI 自动处理加载状态(显示加载动画)
方法2:如果你想完全手动控制加载(更灵活)
$('#deptTree').tree({
onBeforeExpand: function(node){
// 手动设置本次加载的url(可以带额外参数)
$('#deptTree').tree('options').url = 'get_children.php?parentId=' + node.id + '&type=dept';
}
});
方法3:结合左侧布局 + 右侧内容(经典后台部门树)
<div class="easyui-layout" data-options="fit:true">
<div data-options="region:'west',title:'部门架构',split:true" style="width:280px;">
<ul id="deptTree" class="easyui-tree" data-options="url:'get_parent_nodes.php',lines:true"></ul>
</div>
<div data-options="region:'center',title:'部门详情'">
<div id="deptInfo" style="padding:20px;">
请在左侧选择一个部门查看详情
</div>
</div>
</div>
<script>
$('#deptTree').tree({
onClick: function(node){
$('#deptInfo').html('<h3>' + node.text + '</h3><p>部门ID:' + node.id + '</p><p>加载状态:已加载子节点</p>');
// 实际可以:$('#deptInfo').panel('refresh', 'dept_detail.php?id=' + node.id);
}
});
</script>
你现在直接复制方法1的完整代码 + PHP接口示例,放到服务器运行,就能看到一个超级高效的父/子节点懒加载树了!
数据量再大也不怕,只加载当前需要的层级,性能完美。
想要我给你一个完整的部门管理示例(父子懒加载树 + 点击显示详情 + 添加/删除节点 + 保存到数据库)?
或者你告诉我你的数据结构(比如字段叫pid、category_name、is_leaf),我2分钟帮你改好loadFilter和接口逻辑,复制就能跑!
快说说你的具体场景,我手把手帮你搞定,5分钟内看到丝滑的父/子节点加载树!