ant-design-vue Tree 树形控件完全指南:从 API 详解到源码级实现原理
ant-design-vue Tree 树形控件完全指南从 API 详解到源码级实现原理【免费下载链接】ant-design-vue An enterprise-class UI components based on Ant Design and Vue. 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-vue多层次的结构列表在业务系统中无处不在——文件夹目录、组织架构、生物分类、国家地区世间万物的大多数结构都是树形结构。ant-design-vue 的Tree树形控件正是为展现这种层级关系而设计它完整支持展开/收起、节点选择、复选框勾选、异步加载、拖拽排序、虚拟滚动等交互能力并内置了适合文件目录场景的DirectoryTree。本文以 ant-design-vue 仓库中 components/tree/index.zh-CN.md 官方文档为骨架结合Tree.tsx、DirectoryTree.tsx、vc-tree底层实现与仓库内 13 个 demo 示例系统讲解 Tree 的全部配置项、事件、方法与常见实战场景帮助你在项目中熟练驾驭树形控件并理解其底层工作原理。何时使用 Tree树形控件的核心价值在于用最直观的层级缩进和展开收起完整展现数据的父子关系。当你的业务数据满足以下特征时优先考虑使用Tree数据存在明确的父子层级如文件夹、组织架构、类目体系需要交互能力展开/收起、选择、勾选、拖拽、右键菜单来浏览和操作层级数据需要在大数据量下保持良好的浏览性能配合虚拟滚动。快速上手基本用法Tree 既支持通过treeData数据驱动渲染也支持旧式直接以a-tree-node子组件手动构造节点。官方推荐使用treeData仓库源码 Tree.tsx 中也会对仅使用slots.default而不传treeData的写法发出弃用警告。以官方基础示例 demo/basic.vue 为例一个集成了勾选、选中、展开、禁用、自定义标题渲染的最简用法如下template a-tree v-model:expandedKeysexpandedKeys v-model:selectedKeysselectedKeys v-model:checkedKeyscheckedKeys checkable :tree-datatreeData template #title{ title, key } span v-ifkey 0-0-1-0 stylecolor: #1890ff{{ title }}/span template v-else{{ title }}/template /template /a-tree /template script langts setup import { ref, watch } from vue; import type { TreeProps } from ant-design-vue; const treeData: TreeProps[treeData] [ { title: parent 1, key: 0-0, children: [ { title: parent 1-0, key: 0-0-0, disabled: true, // 禁用整节点 children: [ { title: leaf, key: 0-0-0-0, disableCheckbox: true }, // 仅禁用复选框 { title: leaf, key: 0-0-0-1 }, ], }, { title: parent 1-1, key: 0-0-1, children: [{ key: 0-0-1-0, title: sss }] }, ], }, ]; const expandedKeys refstring[]([0-0-0, 0-0-1]); const selectedKeys refstring[]([0-0-0, 0-0-1]); const checkedKeys refstring[]([0-0-0, 0-0-1]); /script这里演示了三个关键能力v-model 双向绑定expandedKeys展开、selectedKeys选中、checkedKeys勾选均可通过v-model:前缀实现受控绑定节点级控制disabled禁用整节点、disableCheckbox仅禁用该节点复选框插槽定制通过#title插槽拿到{ title, key, dataRef }等上下文自定义标题渲染。Tree props完整配置详解官方文档共定义了 25 个Tree配置项下表在保留文档原意的基础上结合 Tree.tsx 中的 props 定义补充了类型与默认值细节。参数说明类型默认值版本allowDrop是否允许拖拽时放置在该节点({ dropNode, dropPosition }) boolean-autoExpandParent是否自动展开父节点搜索联动场景常用booleanfalseblockNode是否节点占据一整行拖拽/目录树场景常用booleanfalsecheckable节点前添加 Checkbox 复选框booleanfalsecheckedKeys (v-model)受控选中复选框的树节点。注意父子关联传入父节点 key 则子节点自动选中全部子节点 key 都传入时父节点也自动选中。当同时设置checkable与checkStrictly时其值为含checked与halfChecked属性的对象父子选中不再关联string[] | number[] | { checked: string[] | number[]; halfChecked: string[] | number[] }[]checkStrictlycheckable 状态下节点选择完全受控父子节点选中状态不再关联booleanfalsedefaultExpandAll默认展开所有节点。异步数据需在数据返回后再实例化建议用v-ifdata.length当存在expandedKeys时defaultExpandAll失效booleanfalsedisabled将整棵树禁用boolfalsedraggable设置节点可拖拽booleanfalseexpandedKeys (v-model)受控展开指定的树节点string[] | number[][]fieldNames替换 treeNode 中 title、key、children 字段为 treeData 中对应的字段object{ children: children, title: title, key: key }3.0.0filterTreeNode按需筛选树节点高亮返回 true 表示命中function(node)-height设置虚拟滚动容器高度设置后内部节点不再支持横向滚动number-loadData异步加载数据展开节点时触发function(node)-loadedKeys受控已经加载的节点需配合loadData使用string[] | number[][]multiple支持点选多个节点节点本身非复选框booleanfalseselectable是否可选中booleantrueselectedKeys (v-model)受控设置选中的树节点string[] | number[]-showIcon是否展示 TreeNode title 前的图标无默认样式置 true 后需自行定义图标与相关样式booleanfalseshowLine是否展示连接线常用于文件目录结构boolean | { showLeafIcon: boolean }3.0falseswitcherIcon自定义展开/折叠图标插槽参数含 active、checked、expanded、loading、selected、halfChecked、title、key、children、dataRef、data、defaultIcon、switcherCls 等v-slot-title自定义标题旧 API推荐使用#title插槽slot-2.0.0treeDatatreeNodes 数据设置后无需手动构造 TreeNode 节点key 在整个树范围内必须唯一TreeNode[]--virtual设置 false 时关闭虚拟滚动booleantrue3.0源码中的默认值佐证Tree.tsx 通过initDefaultProps显式声明了checkable: false、selectable: true、showIcon: false、blockNode: false四个默认值其余未声明默认值的项由底层vc-treecomponents/vc-tree/props.ts接管。值得注意的源码细节虚拟滚动默认开启Tree.tsx中virtual直接取useConfigInject(tree, props)返回的全局配置Tree.tsx默认值true渲染时通过virtual{virtual.value}传给底层VcTree虚拟列表行高固定 28pxitemHeight 28作为默认行高传入Tree.tsx该值决定虚拟滚动的视口计算精度replaceFields已废弃源码通过watchEffect给出 dev 警告Tree.tsx并在渲染时用fieldNames props.replaceFields做兼容新项目请一律使用fieldNamesRTL 支持当 ConfigProvider 的direction为rtl时Tree 自动追加-rtl样式类Tree.tsx。数据驱动treeData 与字段映射 fieldNamestreeData的数据结构为DataNode定义见 components/vc-tree/interface.tsxinterface DataNode extends BasicDataNode { children?: DataNode[]; key: string | number; // 全树唯一 title?: any; // 节点标题可为字符串或 VNode }自定义字段映射 fieldNames当后端返回的字段名不是title/key/children时无需改造接口直接映射即可。参考示例 demo/replaceFields.vuea-tree v-model:expandedKeysexpandedKeys v-model:selectedKeysselectedKeys v-model:checkedKeyscheckedKeys checkable :tree-datatreeData :field-namesfieldNames template #title{ name, key } span v-ifkey 0-0-1 stylecolor: #1890ff{{ name }}/span template v-else{{ name }}/template /template /a-tree script langts setup const fieldNames: TreeProps[fieldNames] { children: child, title: name, }; const treeData ref([ { name: parent 1, key: 0-0, child: [ /* ... */ ] }, ]); /script注意fieldNames的类型定义components/vc-tree/interface.tsx支持title、key、children三个字段的任意组合替换。字段映射在底层通过fillFieldNames归一化后贯穿数据转换、展开传导、勾选传导等全部逻辑如 DirectoryTree.tsx 中的fillFieldNames(props.fieldNames)。事件系统交互回调解读Tree 共暴露 11 个事件官方文档定义如下事件名称说明回调参数check点击复选框触发function(checkedKeys, e: { checked: bool, checkedNodes, node, event })dragenddragend 触发时调用function({ event, node })dragenterdragenter 触发时调用function({ event, node, expandedKeys })dragleavedragleave 触发时调用function({ event, node })dragoverdragover 触发时调用function({ event, node })dragstart开始拖拽时调用function({ event, node })dropdrop 触发时调用function({ event, node, dragNode, dragNodesKeys })expand展开/收起节点时触发function(expandedKeys, { expanded: bool, node })load节点加载完毕时触发function(loadedKeys, { event, node })rightClick响应右键点击function({ event, node })select点击树节点触发function(selectedKeys, e: { selected: bool, selectedNodes, node, event })从 Tree.tsx 的实现可以看到check、expand、select三个核心事件在发出时会同步派发对应的update:xxxKeys更新事件这正是v-model:checkedKeys/v-model:expandedKeys/v-model:selectedKeys双向绑定得以工作的底层机制。底层事件签名含类型化参数定义在 components/vc-tree/props.ts例如drop的完整参数还包括dropPosition-1/0/1 分别表示放置在上方/内部/下方与dropToGap这在拖拽重排数据时非常关键详见下文拖拽示例。复选框勾选的父子关联原理checkedKeys的父子联动并非简单约定而是由底层算法fillConductCheck保证的components/vc-tree/utils/conductUtil.ts自上而下传导父节点被勾选时所有未禁用的子节点 key 被递归加入checkedKeys自下而上回填从叶子层向上若某父节点的子节点全部被勾选则父节点置为勾选若仅部分勾选父节点进入halfCheckedKeys半选状态禁用边界disabled、disableCheckbox或checkable false的节点isCheckDisabled判定不参与传导既不会被自动勾选也不会被自动回填。当设置checkStrictly后该传导被关闭此时checkedKeys需传入{ checked, halfChecked }对象形式以区分勾选与半选。Tree 方法scrollTo名称说明scrollTo({ key: string | number; align?: top | bottom | auto; offset?: number })虚拟滚动下滚动到指定 key 条目方法通过组件 ref 暴露Tree.tsx 中expose了scrollTo以及selectedKeys、checkedKeys、halfCheckedKeys、loadedKeys、loadingKeys、expandedKeys等计算属性方便父组件在受控场景下读取最新状态script langts setup import { ref } from vue; const treeRef ref(); // 在虚拟滚动树中定位到某个节点 const jumpTo () { treeRef.value?.scrollTo({ key: 0-0-0-1, align: top, offset: 0 }); }; /script template a-tree reftreeRef :height233 :tree-datatreeData / /templateTreeNode节点级配置当你选择以子组件方式构造节点旧式写法而非使用treeData时TreeNode提供以下节点级配置官方文档表格参数说明类型默认值版本checkable当树为 checkable 时设置独立节点是否展示 Checkboxboolean-class节点的 classstring-disableCheckbox禁掉 checkboxbooleanfalsedisabled禁掉响应booleanfalseicon自定义图标可接收组件props 为当前节点 propsslot | slot-scope-isLeaf设置为叶子节点设置了loadData时有效boolean-key被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意整个树范围内所有节点的 key 值不能重复string | number内部计算出的节点位置selectable设置节点是否可被选中booleantruestyle节点的 stylestring | object-title标题string---节点级属性同样可以直接写在treeData的节点对象上BasicDataNode定义见 components/vc-tree/interface.tsx因此在数据驱动写法下每个节点对象都可以声明自己的disabled、disableCheckbox、isLeaf、selectable、checkable等属性。DirectoryTree内置目录树DirectoryTree是 Tree 的场景化封装专为文件资源管理器式的目录浏览设计在 index.tsx 中随Tree、TreeNode一并导出并注册为全局组件。DirectoryTree props参数说明类型默认值expandAction目录展开逻辑可选false、click、dblclickstringclick与普通 Tree 的区别源码佐证默认展示文件夹图标源码默认showIcon: trueDirectoryTree.tsx并通过getIcon按节点状态渲染图标——叶子节点为FileOutlined文件夹展开为FolderOpenOutlined、收起为FolderOutlinedDirectoryTree.tsx默认整行块级展示blockNode强制为true点击/双击展开expandAction: click时点击文件夹即触发展开内部通过 200ms 防抖debounce(expandFolderNode, 200, { leading: true })调用底层onNodeExpandDirectoryTree.tsx并在 shift/ctrl/meta 组合键按下时跳过展开以保留多选手势原生多选体验multiple模式下支持ctrl(Windows) /command(Mac) 点选追加、shift范围连选。范围选中的 key 集合由 utils/dictUtil.ts 中的calcRangeKeys基于展开态节点计算只考虑已展开节点以优化性能选中的节点列表则经convertDirectoryKeysToNodes还原。参考示例 demo/directory.vuea-directory-tree v-model:expandedKeysexpandedKeys v-model:selectedKeysselectedKeys multiple :tree-datatreeData /实战场景一异步加载loadData点击展开节点时才向后端请求子级数据适用于大型组织架构、动态目录等场景。参考 demo/dynamic.vuea-tree v-model:expandedKeysexpandedKeys v-model:selectedKeysselectedKeys :load-dataonLoadData :tree-datatreeData / script langts setup const treeData refTreeProps[treeData]([ { title: Expand to load, key: 0 }, { title: Expand to load, key: 1 }, { title: Tree Node, key: 2, isLeaf: true }, // 标记为叶子不触发加载 ]); const onLoadData: TreeProps[loadData] treeNode { return new Promisevoid(resolve { if (treeNode.dataRef.children) { resolve(); // 已有子级无需再加载 return; } setTimeout(() { treeNode.dataRef.children [ { title: Child Node, key: ${treeNode.eventKey}-0 }, { title: Child Node, key: ${treeNode.eventKey}-1 }, ]; treeData.value [...treeData.value]; // 触发响应式更新 resolve(); }, 1000); }); }; /script要点loadData必须返回 Promise加载完成后通过替换treeData引用treeData.value [...treeData.value]触发重渲染不希望展开时请求的节点用isLeaf: true标记为叶子若需精确控制已加载状态可配合受控的loadedKeys加载过程 Tree 会自动展示 loading 图标见 iconUtil.tsxloading 状态下渲染LoadingOutlined。实战场景二搜索高亮可搜索树是后台管理系统的标配。核心思路监听搜索词 → 计算命中节点的所有祖先 key→ 更新expandedKeys并配合autoExpandParent自动展开父级标题命中部分用#title插槽高亮。参考 demo/search.vuea-input-search v-model:valuesearchValue stylemargin-bottom: 8px placeholderSearch / a-tree :expanded-keysexpandedKeys :auto-expand-parentautoExpandParent :tree-datagData expandonExpand template #title{ title } span v-iftitle.indexOf(searchValue) -1 {{ title.substring(0, title.indexOf(searchValue)) }} span stylecolor: #f50{{ searchValue }}/span {{ title.substring(title.indexOf(searchValue) searchValue.length) }} /span span v-else{{ title }}/span /template /a-tree script langts setup watch(searchValue, value { // 遍历 dataList 找到所有命中节点向上回溯其父级 key 并去重 const expanded dataList .map(item (item.title.indexOf(value) -1 ? getParentKey(item.key, gData.value) : null)) .filter((item, i, self) item self.indexOf(item) i); expandedKeys.value expanded; autoExpandParent.value true; // 重新展开父节点 }); /script搜索时需自行实现getParentKey递归回溯父级demo 中给出了完整实现并在onExpand中将autoExpandParent置回false避免用户手动收起节点后又被强制展开。实战场景三拖拽排序draggable设置draggable后节点即可被拖拽到其他节点内部或前后。Tree 提供完整的dragstart/dragenter/dragover/dragleave/drop/dragend事件链但数据重排需要你自行完成——组件只负责交互与回调不直接改写treeData。参考 demo/draggable.vue 的drop处理核心逻辑const onDrop (info: AntTreeNodeDropEvent) { const dropKey info.node.key; // 放置目标节点 const dragKey info.dragNode.key; // 被拖拽节点 const dropPos info.node.pos.split(-); const dropPosition info.dropPosition - Number(dropPos[dropPos.length - 1]); // dropPosition: -1 放置到目标节点前1 放置到目标节点后0 放入内部 // 1. 从 treeData 中摘除被拖拽节点 // 2. 按 dropToGap / dropPosition / 目标节点展开状态判断插入位置 // 3. 重新赋值 gData.value 触发更新 };关键判定逻辑info.dropToGap false放入目标节点内部作为其子级dropToGap true且目标节点有子级、已展开、dropPosition 1追加为目标节点的最后一个子级其余情况按dropPosition -1插入到目标节点前或1插入到目标节点后处理。若需要对放置位置做精细化限制可通过allowDrop: ({ dropNode, dropPosition }) boolean实现底层类型AllowDropOptions见 components/vc-tree/props.ts。实战场景四虚拟滚动virtual / height当节点数量达到数千级时默认开启的虚拟滚动virtual: true可保证流畅滚动。参考 demo/virtual-scroll.vuea-tree v-model:selectedKeysselectedKeys v-model:checkedKeyscheckedKeys default-expand-all checkable :height233 !-- 设置高度即切换为虚拟滚动 -- :tree-datadig() !-- 递归生成 10×10×10 规模数据 -- /注意文档中的两点约束设置height后虚拟列表被激活内部节点不再支持横向滚动横向内容将被裁剪若业务上不需要虚拟化可显式:virtualfalse关闭。配合scrollTo方法可在虚拟滚动树中实现定位到某个节点的导航能力。实战场景五连接线、自定义图标与右键菜单showLine 连接线文件目录场景常用showLine开启节点间的连接线示例 demo/line.vue。它接受boolean或{ showLeafIcon: boolean }3.0。连接线模式下展开/收起图标默认切换为MinusSquareOutlined/PlusSquareOutlined叶子节点默认渲染FileOutlined均可在 utils/iconUtil.tsx 中看到完整分支。switcherIcon 自定义展开/折叠图标通过#switcherIcon插槽接管展开/收起图标插槽参数中的switcherCls用于保持图标与默认样式对齐defaultIcon为默认图标可作兜底示例 demo/switcher-icon.vuea-tree v-model:expandedKeysexpandedKeys show-line :tree-datatreeData template #switcherIcon{ switcherCls } down-outlined :classswitcherCls / /template /a-tree当switcherIcon传入函数/插槽时底层会注入{ ...nodeProps, defaultIcon, switcherCls }上下文iconUtil.tsx因此你可以针对不同节点状态展开、选中、加载中等渲染不同图标。自定义节点图标icon / showIconshowIcon开启 title 前图标位配合#icon插槽按节点 key 或选中状态定制图标示例 demo/customized-icon.vue。注意官方文档提示showIcon只负责展示没有默认样式开启后需要自行定义图标相关样式。rightClick 右键菜单用rightClick拿到{ event, node }结合a-dropdown的contextmenu触发方式即可实现节点级右键菜单示例 demo/context-menu.vuea-tree v-model:expandedKeysexpandedKeys :tree-datatreeData template #title{ key: treeKey, title } a-dropdown :trigger[contextmenu] span{{ title }}/span template #overlay a-menu click({ key: menuKey }) onContextMenuClick(treeKey, menuKey) a-menu-item key11st menu item/a-menu-item a-menu-item key22nd menu item/a-menu-item /a-menu /template /a-dropdown /template /a-treeFAQshowLine 时如何隐藏子节点图标官方 FAQ 明确说明连接线模式下出现在子节点前的图标实际上是通过switcherIcon渲染出来的叶子节点默认FileOutlined。若不需要该图标可通过覆盖对应样式类隐藏例如/* 隐藏 showLine 模式下叶子节点的文件图标 */ .ant-tree-show-line .ant-tree-switcher-leaf-line { display: none; }从 iconUtil.tsx 的实现看叶子节点在showLine且showLeafIcon为 falseshowLine传对象形式时渲染的是-switcher-leaf-line这个纯样式 span连接线的占位否则渲染FileOutlined-switcher-line-icon。因此更精确的做法是按需配置!-- 连接线保留、但叶子节点不展示文件图标 -- a-tree :show-line{ showLeafIcon: false } :tree-datatreeData /源码结构导览若想深入 Tree 的实现建议按以下路径阅读components/tree/Tree.tsxATree组件主体props 定义、默认值、事件转发、expose方法、样式注入CSS-in-JScomponents/tree/DirectoryTree.tsx目录树封装图标逻辑、expandAction、shift/ctrl 多选components/tree/index.tsx导出Tree、TreeNode、DirectoryTree及类型并提供app.use()全局注册components/vc-tree/props.ts底层树全部 props 与事件签名与 ant-design 的 rc-tree 对齐components/vc-tree/utils/conductUtil.ts勾选父子传导算法fillConductCheckcomponents/vc-tree/utils/treeUtil.tstreeData与实体关系keyEntities转换、fieldNames归一化components/tree/utils/iconUtil.tsx展开/折叠/叶子图标渲染规则components/tree/utils/dictUtil.ts目录树范围选择shift 连选计算components/tree/demo13 个官方示例basic、dynamic、search、draggable、directory、line、virtual-scroll、context-menu、switcher-icon、replaceFields、customized-icon 等是最佳上手素材components/tree/tests/demo.test.js通过demoTest(tree)对全部 demo 做渲染冒烟测试可作为组件行为的回归验证参考。结语ant-design-vue 的 Tree 是一个开箱即用、深可定制的树形组件数据驱动的treeDatafieldNames让它能无缝对接任意后端数据结构v-model受控三件套checked/selected/expanded与完整事件体系覆盖绝大多数交互诉求DirectoryTree、异步加载、虚拟滚动、拖拽与右键菜单等能力则支撑起文件管理、组织架构、权限树等真实业务场景。理解其底层勾选传导算法与受控事件转发机制后即使遇到高度定制化的需求也能基于源码从容扩展。【免费下载链接】ant-design-vue An enterprise-class UI components based on Ant Design and Vue. 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-vue创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考