获取ztree选中项的核心方法是监听zTree的onCheck或onClick回调事件,并通过treeObj.getCheckedNodes(true)或treeObj.getSelectedNodes()来拿到节点数据。很多人在服务器端纠结怎么拿到前端选的节点,其实zTree的选中逻辑完全在前端完成,服务端只需要接收前端传过来的节点ID数组就行,下面我把完整的实现路径和常见坑位一次讲清楚。
zTree选中项的两种核心形态与获取原理
zTree的“选中”有两种完全不同的含义,搞混了就会出现“明明勾选了却拿不到数据”的尴尬情况。
复选框勾选 vs 节点高亮选中
- 勾选(checked):节点前面有复选框,用户点击复选框后节点进入勾选状态,这种状态通过
getCheckedNodes(true)获取,true代表只取被勾选的节点。 - 高亮选中(selected):用户点击节点文字本身,节点背景变蓝,表示当前焦点选中,这种状态通过
getSelectedNodes()获取,返回的是一个数组,通常只有一个元素。
如果你用的是checkbox模式,默认情况下点击复选框不会触发selected事件,但会触发onCheck回调,如果两种状态都需要,就要在setting中同时配置check.enable = true和selected相关逻辑。
服务端到底需要什么
服务端不需要知道节点对象本身,只需要节点的唯一标识字段,通常是id,所以完整链路是:前端拿到选中节点数组 → 提取每个节点的id → 通过ajax或form提交到t服务器 → 服务端解析id列表做后续处理。
通过onCheck回调实时获取选中节点
这是zTree最常见的场景:树形结构带复选框,用户勾选后需要把选中的部门、权限、分类等ID提交给服务端。
基础配置代码示例
在初始化zTree的setting中,必须开启check功能并绑定回调:
var setting = {
check: {
enable: true,
chkboxType: { "Y": "ps", "N": "ps" }
},
callback: {
onCheck: function(event, treeId, treeNode) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
var nodes = treeObj.getCheckedNodes(true);
var idList = [];
for (var i = 0; i < nodes.length; i++) {
idList.push(nodes[i].id);
}
console.log(idList); // 这里拿到所有勾选节点的id数组
}
}
};
关键点:getCheckedNodes(true)的参数true表示只返回被勾选的节点,如果写false会返回所有节点(包括未勾选的),这是个容易踩的坑。chkboxType中的"ps"表示父节点和子节点联动,如果你需要父子联动,这个配置不能省。
父子联动时的结果差异
业内专家指出,大多数权限管理场景希望勾选父节点时自动勾选所有子节点,此时getCheckedNodes(true)会返回父节点和所有子节点,数量很多,如果服务端只需要叶子节点(比如只能给最细粒度权限授权),就需要在遍历时过滤:
var leafIds = nodes.filter(function(node) {
return !node.isParent; // 只保留叶子节点
}).map(function(node) {
return node.id;
});
反过来,如果你只需要父节点ID,就过滤node.isParent === true,这个过滤逻辑要跟业务需求严格对应,否则服务端拿到的数据会多或者少。
通过getSelectedNodes获取当前点击选中的节点
有些场景不需要复选框,只需要用户点击树节点后,服务端根据当前选中的节点加载详情,这种情况下用onClick回调加getSelectedNodes()。
标准写法
var setting = {
callback: {
onClick: function(event, treeId, treeNode) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
var selectedNodes = treeObj.getSelectedNodes();
if (selectedNodes.length > 0) {
var selectedNode = selectedNodes[0];
// 把selectedNode.id发给服务端
$.post('/api/getNodeDetail', { id: selectedNode.id }, function(res) {
// 服务端返回详情后渲染
});
}
}
}
};
注意getSelectedNodes()返回数组,即使只选中一个也是数组,虽然zTree单选模式下同一时间只有一个是高亮状态,但代码上还是要用selectedNodes[0]来取,不要直接用selectedNodes操作。
获取父节点与祖先链
如果需要服务端知道当前选中节点的完整路径(比如面包屑导航),可以这样拿:
var parents = selectedNode.getParentNodes(); // 获取所有父节点
var path = parents.map(function(p) { return p.name; }).join(' / ');
zTree的节点对象内置了getParentNodes()和getPath()等方法,不需要自己递归往上找。
zTree中获取选中节点的四种常用方式对比
不同需求对应不同的获取方法,我把最常见的四种列成表格,方便你直接对照使用。
| 场景 | 回调事件 | 获取方法 | 返回值 | 服务端接收内容 |
|---|---|---|---|---|
| 复选框勾选 | onCheck | getCheckedNodes(true) |
数组,包含所有勾选节点 | 所有勾选节点的ID数组 |
| 节点高亮选中 | onClick | getSelectedNodes() |
数组,单选模式下长度1 | 当前节点的ID |
| 所有勾选含半选 | onCheck | getCheckedNodes(false) |
数组,包含未勾选但半选节点 | 需要自行过滤 |
| 动态获取任意时刻选中 | 任意事件 | getZTreeObj(treeId).getCheckedNodes(true) |
数组 | 配合按钮事件使用 |
第四种方式最常用在“确定”按钮的场景:用户随便勾选,点提交时才统一获取一次,而不是每次勾选都触发请求。
服务端接收选中数据的三种提交方式
t服务器接收前端数据的方式取决于你前端怎么提交,zTree本身不负责数据传输,它只负责把选中节点暴露给JavaScript变量。
AJAX POST提交JSON数组
function submitSelected() {
var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
var nodes = treeObj.getCheckedNodes(true);
var ids = nodes.map(function(node) { return node.id; });
$.ajax({
url: '/api/savePermission',
type: 'POST',
data: JSON.stringify({ ids: ids }),
contentType: 'application/json',
success: function(res) {
console.log('提交成功');
}
});
}
服务端(以Spring MVC为例)直接用@RequestBody接收:
@PostMapping("/api/savePermission")
public Result savePermission(@RequestBody Map<String, List<String>> payload) {
List<String> ids = payload.get("ids");
// 业务逻辑
}
Form表单提交隐藏域
如果是不刷页面的传统表单,可以在提交前把选中ID写入隐藏域:
<input type="hidden" id="selectedIds" name="selectedIds">
function beforeSubmit() {
var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
var nodes = treeObj.getCheckedNodes(true);
var ids = nodes.map(function(node) { return node.id; });
document.getElementById("selectedIds").value = ids.join(",");
return true; // 放行提交
}
服务端拿到逗号分隔的字符串后split即可。
同步拼接URL参数
适合GET请求的小数据量场景:
var ids = nodes.map(function(node) { return node.id; }).join(',');
window.location.href = "/page?ids=" + encodeURIComponent(ids);
这种方式不适用于大量节点,URL长度有限制,如果树节点上千个,建议用POST。
zTree异步加载模式下获取选中节点的注意事项
如果你的树是异步加载的(子节点在点击父节点时才从服务端拉取),你会发现getCheckedNodes(true)可能拿不到未加载的子节点,因为zTree只认识已经加载到内存的节点。
半选状态与父节点联动问题
当父节点下只有部分子节点被勾选时,父节点进入半选状态(半勾),getCheckedNodes(true)不会返回这个父节点,因为它的checked属性为false,但它的halfCheck属性为true,如果你需要把半选父节点也传给服务端做特殊处理,可以这样:
var allCheckedNodes = treeObj.getCheckedNodes(true);
var halfCheckedNodes = treeObj.getCheckedNodes(false).filter(function(node) {
return node.halfCheck;
});
未加载子节点的勾选状态
异步加载场景下,如果用户勾选了某个父节点,但它的子节点还没加载出来,zTree会先给父节点打勾,等到子节点加载后,子节点默认继承父节点的勾选状态,但此时getCheckedNodes(true)的结果已经包含了这些新加载的子节点,如果你在用户勾选父节点时就立刻提交服务端,可能服务端只收到父节点ID,子节点ID还没出现。
解决方案:在做“保存”按钮提交前,先强制展开所有节点或者调用treeObj.expandAll(true),让所有子节点加载完成后再获取选中项,如果树很大不能全展开,就根据业务决定是否只接受父节点ID。
根据选中节点获取服务端数据的联动场景
较常见的业务场景是:左侧部门树,右侧显示该部门下的人员列表,点击部门节点时,把部门ID发给服务端,服务端返回人员数据。
后端接口设计
接口路径类似/api/getUsersByDept?deptId=123,返回该部门下的用户列表,前端在onClick回调中获取selectedNode.id,然后发起请求。
需要注意:如果部门树是异步加载的,当点击父部门时selectedNode的id是正常的,但如果点击的节点是后来动态加载的,id已经在数据中,没有问题,真正容易出错的是根节点没有暴露id字段的情况,比如某些树的根节点id为空字符串,提交给服务端会报参数缺失。
多选树配合搜索过滤
还有一种常见需求:树上方有个输入框,用户搜索节点后勾选,然后提交,搜索用的是zTree的treeObj.expandAll(true)配合highlight和show隐藏不匹配节点,此时选中节点依然可以通过getCheckedNodes(true)拿到,但如果搜索过程中节点被隐藏了,选中状态依然保留,这一点需要注意,用户可能看不到隐藏节点已被勾选。
可以在搜索时多一步处理:搜索结束后,把所有已勾选但被隐藏的节点显示出来,或者用文字提示“当前选中了N个节点(含隐藏)”来避免误操作。
常见报错与解决思路
遇到“t服务器拿不到zTree选中项”的问题,通常不是服务端的问题,而是前端取值时机不对。
页面初始化时获取不到
如果你在$(document).ready里立即执行getCheckedNodes(true),此时zTree可能还没渲染完成,必须等onAsyncSuccess(异步加载完成)或onInit事件触发后再取,或者直接用setTimeout延迟100毫秒,但这不够优雅,推荐用回调。
节点ID不是数字类型
服务端如果用int类型接收,前端传入的id是字符串也没关系,只要JSON转换时类型匹配,但如果id本身带其他字符,比如"dept_001",服务端就要用String接收。
多个zTree实例搞混ID
如果页面有两个tree,注意第二个参数treeId要对应实际的ul元素的id,用$.fn.zTree.getZTreeObj("treeDemo")时,字符串必须跟初始化时绑定div的id完全一致,大小写敏感。
性能优化:几千节点时如何高效获取选中项
当树节点数量达到数千甚至上万,getCheckedNodes(true)遍历全部节点会阻塞主线程,页面可能有明显卡顿。
- 用
treeObj.getCheckedNodes(true)直接一次拿全量,这是最简但最慢的方式。 - 可以在节点勾选的onCheck回调里,自己用数组维护选中集合,勾选时添加,取消勾选时删除,这样提交时直接用维护的数组,不遍历树。
- 取消勾选时注意:如果父子联动,取消父节点会级联取消子节点,onCheck回调会被触发多次,维护数组时要处理好去重。
推荐用维护数组的方式处理大型树,具体做法是:
var selectedIdSet = new Set();
function handleCheck(event, treeId, treeNode) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
var nodes = treeObj.getCheckedNodes(true);
selectedIdSet.clear();
nodes.forEach(function(node) {
selectedIdSet.add(node.id);
});
// 或者用增量更新,性能更快
}
与后端框架的集成实践
如果你用的是Java Spring Boot,接收前端传来的数组时,建议使用DTO类:
public class PermissionSaveDTO {
private List<String> ids;
// getter setter
}
如果是Python Flask,直接拿request.json.get('ids'),如果是Node.js Express,req.body.ids就是数组,不同语言没有本质区别,关键在于前端JSON格式要标准。
行业共识认为,前后端交互最稳妥的方式是统一用JSON数组传ID,避免用逗号拼接字符串,因为节点ID本身可能包含逗号或特殊字符。
Q&A:关于zTree选中项获取的常见疑问
Q:zTree的getCheckedNodes返回的是JSON对象还是节点对象?
A:返回的是节点对象数组,每个节点包含id、name、isParent、checked等属性,如果你要传给服务端,务必自己提取需要的字段,不要把整个节点对象序列化传给服务端,那样会附带大量无用属性,浪费带宽。
Q:如何在zTree初始化时预选某些节点?
A:使用treeObj.checkNode(node, true, true)方法,在渲染完成后循环需要选中的节点执行该方法,也可以在后端返回zTree数据时直接给节点设置checked: true属性,zTree初始化时会自动渲染勾选状态,注意如果是异步加载,动态加载出来的子节点需要在onAsyncSuccess回调里根据服务端返回的checked字段处理。
Q:t服务器(第三方服务器)如何获取zTree的选中项?
A:t服务器本身无法直接操作前端DOM对象,它只能接收前端发送的HTTP请求,你需要在前端获取选中项后,通过ajax、fetch或表单提交的方式把这些数据作为参数传递给t服务器,如果t服务器返回HTML片段,可以在这个片段里用JavaScript嵌入zTree初始化代码,然后在服务端处理提交过来的节点ID数据。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/794950.html


