TinyVue Tree 树形控件完全指南:层级数据展示的瑞士军刀
本文基于 OpenTiny TinyVue 官方 API 与示例整理,组件包:
@opentiny/vue
如果你做过后台管理系统,一定见过这种场景:左侧一棵目录树,右侧一堆表格,中间还夹着权限勾选------Tree 组件就是干这个的。TinyVue 的 Tree 组件功能相当全面,从基础展示到懒加载、拖拽、编辑、右键菜单,基本把树形交互的坑都填平了。
快速上手
Tree 通过 data 属性传入数据源,默认读取每项的 label 和 children 字段:
vue
<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 做字段映射:
vue
<tiny-tree
:data="data"
:props="{ children: 'subs', label: 'name', disabled: 'disabled', isLeaf: 'isLeaf' }"
/>
disabled:控制节点禁用isLeaf:懒加载模式下标记叶子节点,点了不再请求子数据
节点高亮与选中
高亮和查询都依赖 node-key 指定唯一标识:
vue
<tiny-tree
node-key="id"
:data="data"
highlight-current
:current-node-key="'2-1'"
@current-change="onCurrentChange"
/>
常用实例方法:
js
// 查询
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)
开启多选:
vue
<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:
js
// 查询
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 是标配:
vue
<tiny-tree lazy :load="load" @load-data="onLoadData" />
js
function load(node, resolve) {
if (node.level === 0) {
// 首次加载根节点
resolve([
{ id: '1', label: '数据 1' },
{ id: '2', label: '数据 2' }
])
} else if (node.data) {
// 点击后加载子节点
fetchChildren(node.data.id).then(children => resolve(children))
}
}
注意:懒加载模式下 data 属性无效,子数据全靠 resolve() 回调返回。props.isLeaf 标记叶子节点后,点击不再触发 load。
节点增删改
不用改原始 data,直接调实例方法:
js
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()。
拖拽
vue
<tiny-tree
draggable
:allow-drag="allowDrag"
:allow-drop="allowDrop"
@node-drop="onDrop"
/>
js
function allowDrag(node) {
return !node.data.disabled
}
function allowDrop(srcNode, targetNode, type) {
// type: 'prev' | 'inner' | 'next'
return type !== 'inner' // 示例:禁止拖入节点内部
}
拖拽过程还会触发 node-drag-start、node-drag-enter、node-drag-over、node-drag-leave、node-drag-end 等事件。频率较高,建议加节流。
编辑模式
适合可维护的目录树场景:
js
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。
过滤与平铺视图
搜索过滤:
vue
<tiny-tree
ref="treeRef"
:data="data"
node-key="id"
:filter-node-method="filterNode"
highlight-query
/>
<!-- 触发过滤 -->
<tiny-input v-model="keyword" @input="treeRef.filter(keyword)" />
js
function filterNode(value, data) {
if (!value) return true
return data.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