TinyVue Tree 树形控件完全指南:层级数据展示的瑞士军刀
本文基于 OpenTiny TinyVue 官方 API 与示例整理,组件包:
@opentiny/vue
如果你做过后台管理系统,一定见过这种场景:左侧一棵目录树,右侧一堆表格,中间还夹着权限勾选——Tree 组件就是干这个的。TinyVue 的Tree组件功能相当全面,从基础展示到懒加载、拖拽、编辑、右键菜单,基本把树形交互的坑都填平了。
快速上手
Tree 通过data属性传入数据源,默认读取每项的label和children字段:
<template> <tiny-tree :data="data" default-expand-all @node-click="nodeClick" /> </template> <script setup> import { ref } from 'vue' import { TinyTree } from '@opentiny/vue' const data = ref([ { id: '1', label: '数据 1', children: [ { id: '1-1', label: '数据 1-1', children: [{ id: '1-1-1', label: '数据 1-1-1' }] }, { id: '1-2', label: '数据 1-2' } ] }, { id: '2', label: '数据 2', children: [ { id: '2-1', label: '数据 2-1' }, { id: '2-2', label: '数据 2-2' } ] } ]) function nodeClick(data, node, vm) { console.log('点击节点:', data.label) } </script>几个常用外观属性:
| 属性 | 说明 | 默认值 |
|---|---|---|
show-line | 是否显示连接线 | false |
size | 组件尺寸:medium/small | - |
indent | 相邻级水平缩进(px) | 18 |
非标准数据格式
后端返回的字段名不是label/children?用props做字段映射:
<tiny-tree :data="data" :props="{ children: 'subs', label: 'name', disabled: 'disabled', isLeaf: 'isLeaf' }" />disabled:控制节点禁用isLeaf:懒加载模式下标记叶子节点,点了不再请求子数据
节点高亮与选中
高亮和查询都依赖node-key指定唯一标识:
<tiny-tree node-key="id" :data="data" highlight-current :current-node-key="'2-1'" @current-change="onCurrentChange" />常用实例方法:
// 查询treeRef.value.getCurrentNode()treeRef.value.getCurrentKey()treeRef.value.getNode('2-1')treeRef.value.getNodePath('2-1-1')// 设置高亮treeRef.value.setCurrentKey('2-1')treeRef.value.setCurrentNode(nodeData)实用技巧:通过getNode()拿到的节点对象,可以访问parent、childNodes、nextSibling等属性,还能调用expand()/collapse()控制展开收起——比手动改data优雅多了。
展开控制
| 属性 / 方法 | 说明 |
|---|---|
default-expand-all | 初始全部展开 |
default-expanded-keys | 初始展开指定 key 数组(需配合node-key) |
expand-on-click-node | 点击文字是否展开,默认true;设为false则只有点图标才展开 |
expandAllNodes(true/false) | 一键全部展开/收起 |
accordion | 手风琴模式,同时只展开一个同级节点 |
监听@node-expand和@node-collapse即可追踪展开状态变化。
多选模式(Checkbox)
开启多选:
<tiny-tree node-key="id" :data="data" show-checkbox :check-on-click-node="true" :default-checked-keys="['2']" :expand-on-click-node="false" />严格模式check-strictly:父子勾选互不影响,适合权限分配等场景。
勾选相关 API:
// 查询treeRef.value.getCheckedKeys(leafOnly)treeRef.value.getCheckedNodes(leafOnly,includeHalfChecked)treeRef.value.getHalfCheckedKeys()// 设置treeRef.value.setCheckedKeys(['1','2-1'])treeRef.value.setChecked(nodeOrKey,checked,deep)事件区别:
@check:触发在被点击的节点上,参数为节点 + 整体勾选状态@check-change:每个状态变化的节点都会触发,一次勾选可能连发多个
懒加载
大数据量或按需加载子节点时,lazy+load是标配:
<tiny-tree lazy :load="load" @load-data="onLoadData" />functionload(node,resolve){if(node.level===0){// 首次加载根节点resolve([{id:'1',label:'数据 1'},{id:'2',label:'数据 2'}])}elseif(node.data){// 点击后加载子节点fetchChildren(node.data.id).then(children=>resolve(children))}}注意:懒加载模式下data属性无效,子数据全靠resolve()回调返回。props.isLeaf标记叶子节点后,点击不再触发load。
节点增删改
不用改原始data,直接调实例方法:
treeRef.value.insertBefore(newNode,targetKey)// 前插treeRef.value.insertAfter(newNode,targetKey)// 后插treeRef.value.append(newNode,targetKey)// 追加为子节点(顶部)treeRef.value.remove(targetKey,isSaveChildNode)// 删除;true 时子节点上移treeRef.value.updateKeyChildren(key,children)// 替换全部子节点更新子节点又要保留原有子节点?先getNode()拿到children,改完再updateKeyChildren()。
拖拽
<tiny-tree draggable :allow-drag="allowDrag" :allow-drop="allowDrop" @node-drop="onDrop" />functionallowDrag(node){return!node.data.disabled}functionallowDrop(srcNode,targetNode,type){// type: 'prev' | 'inner' | 'next'returntype!=='inner'// 示例:禁止拖入节点内部}拖拽过程还会触发node-drag-start、node-drag-enter、node-drag-over、node-drag-leave、node-drag-end等事件。频率较高,建议加节流。
编辑模式
适合可维护的目录树场景:
treeRef.value.openEdit()// 进入编辑treeRef.value.addNode(parentNode)// 添加子节点并进入编辑treeRef.value.editNode(node)// 编辑指定节点treeRef.value.saveNode()// 保存当前编辑treeRef.value.saveEdit()// 保存全部并返回变更数据treeRef.value.closeEdit()// 取消编辑权限控制:
| 属性 / 方法 | 作用 |
|---|---|
add-disabled-keys/setAddDisabledKeys | 禁止添加 |
edit-disabled-keys/setEditDisabledKeys | 禁止编辑 |
delete-disabled-keys/setDeleteDisabledKeys | 禁止删除 |
delete-node-method | 自定义删除钩子,返回false或 reject 则取消删除 |
编辑事件:open-edit、close-edit、save-edit、add-node、edit-node、delete-node。
过滤与平铺视图
搜索过滤:
<tiny-tree ref="treeRef" :data="data" node-key="id" :filter-node-method="filterNode" highlight-query /> <!-- 触发过滤 --> <tiny-input v-model="keyword" @input="treeRef.filter(keyword)" />functionfilterNode(value,data){if(!value)returntruereturndata.label.includes(value)}view-type="plain"切换平铺视图,配合show-auxi显示上级路径,搜索场景体验更好。
插槽扩展
| 插槽 | 用途 |
|---|---|
default | 自定义节点内容 |
prefix/suffix | 节点前后元素 |
operation | 靠右对齐操作区 |
empty | 无数据时的占位 |
contextmenu | 右键菜单(需show-contextmenu) |
也可用render-content函数属性做 JSX 渲染。
其它实用特性
- 单选模式:
show-radio,但官方建议尽量不用,多选用 checkbox 更灵活 - 右键菜单:
show-contextmenu+contextmenu插槽,用closeMenu()关闭 - 键盘导航:默认支持 ↑↓ 移动、←→ 展开收起、Enter/Space 勾选
- 连接线:
show-line让层级关系一目了然
小结
TinyVue Tree 不是「能展示层级就完事」的基础组件,而是一套完整的树形交互方案:
- 展示层:连接线、尺寸、缩进、自定义图标/插槽
- 交互层:高亮、多选/单选、展开控制、过滤搜索
- 数据层:懒加载、增删改、拖拽排序
- 编辑层:内置编辑模式 + 细粒度权限
下次做组织架构、菜单权限、文件目录,直接<tiny-tree>安排上,别自己用ul > li递归写到怀疑人生。
相关链接
- 组件包:
@opentiny/vue - 官方文档:OpenTiny TinyVue