在企业级前端开发中,树形结构的数据展示是一个常见且复杂的场景。从组织架构图、菜单权限树到商品分类、区域选择,树形控件几乎无处不在。实现一个功能完善的树形控件并不简单——你需要处理异步加载、节点拖拽、复选框联动、节点过滤、编辑删除等一系列交互需求。
ZTree 正是为解决这些复杂需求而生的。它是一个依靠 jQuery 实现的多功能“树插件”,以性能优异、功能丰富、配置灵活著称。尽管在前端框架日新月异的今天,jQuery 的统治地位已不如从前,但在许多传统企业级项目、老旧系统维护以及一些特定的后台管理界面中,ZTree 凭借着其稳定性和开箱即用的丰富 API,依然是开发者在需要处理复杂树结构时的首选利器。
本文将系统全面地介绍 ZTree 的核心知识点,从其设计哲学到核心配置,从节点操作到事件处理,帮助读者建立完整的知识体系,能够熟练运用 ZTree 构建专业的企业级树形组件。
一、ZTree 概述
1.1 什么是 ZTree
ZTree 是一个依靠 jQuery 实现的多功能“树插件”。它以性能优异、功能丰富、配置灵活著称。与很多需要复杂配置的UI框架相比,ZTree 的开箱即用特性显得格外珍贵。同时它自带的一致性API也降低了后期维护的难度。
ZTree 的核心理念可以概括为三个关键词:
1.2 ZTree 的核心功能
ZTree 的核心功能非常强大,可以满足企业级应用中绝大部分树形结构的展示和操作需求。
1.标准树结构展示
支持 JSON 格式数据,可轻松从后端 API 获取数据渲染
支持父子节点层级无限极
支持节点的展开/收缩动画效果
2.多选/单选/复选框
支持复选框模式(checkbox),方便进行权限分配、多选操作
支持单选按钮模式(radio),适用于只能选择一个节点的场景(如分类选择)
支持父子节点联动:勾选父节点自动勾选所有子节点;勾选所有子节点自动勾选父节点
3.节点编辑(增删改)
支持增加节点(addNodes)
支持修改节点名称(updateNode)
支持删除节点(removeNode)
支持节点拖拽排序(drag)
4.节点拖拽
支持树内拖拽排序,可控制拖拽的范围和规则,是菜单排序、分类排序的绝佳帮手
支持跨树拖拽(多棵树之间拖拽移动节点)
可自定义拖拽时的图标、提示信息
5.异步加载
支持异步加载(lazy load)子节点数据,适用于节点数量庞大的情况
支持分页加载,避免一次性加载过多节点导致页面卡顿
6.节点过滤与高亮
支持搜索功能,可根据输入的关键词实时过滤节点
支持模糊匹配,高亮显示匹配到的文字
支持自定义过滤规则
7.节点状态标记
设置节点的半选状态(chkHalf),精准表达权限继承关系
设置节点的禁用状态(chkDisabled),防止节点被操作
设置节点的隐藏状态(isHidden)
二、安装与快速入门
2.1 获取 ZTree
方式一:官方网站下载
访问 ZTree 官网(ztree.me)下载最新版本的压缩包,解压后得到以下核心文件:
jquery.ztree.core.js:核心功能库(基础功能)
jquery.ztree.excheck.js:扩展库,实现复选框/单选框功能
jquery.ztree.exedit.js:扩展库,实现编辑、拖拽功能
jquery.ztree.exhide.js:扩展库,实现节点隐藏功能
zTreeStyle.css:默认样式文件
方式二:CDN 引入
<!-- 引入 jQuery(必须在 ZTree 之前) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 引入 ZTree 核心库 -->
<script src="https://cdn.jsdelivr.net/npm/zTree.v3@3.5.98/js/jquery.ztree.core.min.js"></script>
<!-- 如需复选框/单选框,需引入此扩展 -->
<script src="https://cdn.jsdelivr.net/npm/zTree.v3@3.5.98/js/jquery.ztree.excheck.min.js"></script>
<!-- 如需编辑/拖拽,需引入此扩展 -->
<script src="https://cdn.jsdelivr.net/npm/zTree.v3@3.5.98/js/jquery.ztree.exedit.min.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/zTree.v3@3.5.98/css/zTreeStyle/zTreeStyle.css">
方式三:npm 安装(工程化项目)
npm install ztree-v3
2.2 第一个 ZTree 示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ZTree 快速入门</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/zTree.v3@3.5.98/css/zTreeStyle/zTreeStyle.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/zTree.v3@3.5.98/js/jquery.ztree.core.min.js"></script>
</head>
<body>
<!-- 创建一个用于存放树的 ul 容器 -->
<ul id="treeDemo" class="ztree"></ul>
<script>
// 1. 配置参数
const setting = {
view: {
showLine: true, // 是否显示连接线
selectedMulti: false // 是否允许多选
},
data: {
simpleData: {
enable: true, // 启用简单 JSON 数据格式
idKey: "id", // 节点 id
pIdKey: "pId", // 父节点 id
rootPId: 0 // 根节点 id
}
}
};
// 2. 准备数据(使用简单的父子关系格式)
const zNodes = [
{ id: 1, pId: 0, name: "父节点1", open: true },
{ id: 11, pId: 1, name: "子节点1-1" },
{ id: 12, pId: 1, name: "子节点1-2" },
{ id: 2, pId: 0, name: "父节点2", open: true },
{ id: 21, pId: 2, name: "子节点2-1" }
];
// 3. 初始化树
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
</script>
</body>
</html>
2.3 在 Vue 项目中集成 ZTree
如果你的项目使用 Vue 但仍需使用 ZTree,需要进行一些封装处理。
<template>
<div>
<ul ref="ztree" class="ztree"></ul>
</div>
</template>
<script>
import 'ztree-v3/css/zTreeStyle/zTreeStyle.css';
import 'ztree-v3/js/jquery.ztree.core.min.js';
import 'ztree-v3/js/jquery.ztree.excheck.min.js';
import 'ztree-v3/js/jquery.ztree.exedit.min.js';
import $ from 'jquery';
export default {
name: 'ZTreeComponent',
props: {
setting: { type: Object, default: () => ({}) },
nodes: { type: Array, default: () => [] }
},
mounted() {
this.initTree();
},
watch: {
nodes: {
handler() {
this.updateTree();
},
deep: true
}
},
methods: {
initTree() {
// 合并默认配置
const defaultSetting = {
view: { showLine: true, selectedMulti: false },
data: { simpleData: { enable: true } },
callback: {
onClick: this.onNodeClick,
onCheck: this.onNodeCheck
}
};
const finalSetting = { ...defaultSetting, ...this.setting };
$.fn.zTree.init($(this.$refs.ztree), finalSetting, this.nodes);
this.treeObj = $.fn.zTree.getZTreeObj(this.$refs.ztree);
},
updateTree() {
if (this.treeObj) {
this.treeObj.destroy();
$.fn.zTree.init($(this.$refs.ztree), this.finalSetting, this.nodes);
this.treeObj = $.fn.zTree.getZTreeObj(this.$refs.ztree);
}
},
onNodeClick(event, treeId, treeNode) {
this.$emit('node-click', treeNode);
},
onNodeCheck(event, treeId, treeNode) {
this.$emit('node-check', treeNode);
},
getCheckedNodes() {
return this.treeObj ? this.treeObj.getCheckedNodes(true) : [];
},
addNode(parentNode, newNode) {
if (this.treeObj && parentNode) {
this.treeObj.addNodes(parentNode, newNode);
}
}
}
};
</script>