CustomTree 树形组件
用于展示层级结构数据,支持展开收起、单选、多选等功能。
基础用法
通过 data 属性传入树形数据,组件会自动渲染层级结构。
vue
<script setup>
import CustomTree from "@/components/custom-tree/index.vue"
// 树形数据结构:value(节点值) + label(显示文本) + children(子节点)
const treeData = [
{ value: "1", label: "系统管理", children: [
{ value: "1-1", label: "用户管理" },
{ value: "1-2", label: "角色管理" },
]},
{ value: "2", label: "系统监控", children: [
{ value: "2-1", label: "系统日志" },
]},
]
</script>
<template>
<custom-tree :data="treeData" />
</template>默认展开
设置 default-expand-all 属性,默认展开所有节点。
vue
<custom-tree :data="treeData" default-expand-all />或通过 default-expanded-keys 指定默认展开的节点。
vue
<custom-tree
:data="treeData"
:default-expanded-keys="['1', '1-1']"
/>多选功能
设置 checkable 属性开启多选功能,通过 checked-keys 绑定选中的节点。
vue
<script setup>
import { ref } from "vue"
import CustomTree from "@/components/custom-tree/index.vue"
const treeData = [
{ id: "1", name: "系统管理", children: [
{ id: "1-1", name: "用户管理" },
{ id: "1-2", name: "角色管理" }
]},
{ id: "2", name: "系统监控" }
]
const checkedKeys = ref(["1-1"])
function handleCheck(keys, info) {
console.log("选中:", keys)
console.log("操作:", info.checked ? "选中" : "取消选中", info.node)
}
</script>
<template>
<custom-tree
:data="treeData"
:checkable="true"
:checked-keys="checkedKeys"
value-key="id"
label-key="name"
@check="handleCheck"
/>
</template>父子联动
默认情况下,选中父节点会自动选中所有子节点,取消同理。设置 check-strictly 属性可取消父子联动。
vue
<!-- 父子不联动 -->
<custom-tree
:data="treeData"
:checkable="true"
:check-strictly="true"
/>半选状态
当部分子节点选中时,父节点会显示半选状态(indeterminate)。
自定义节点内容
通过 content 插槽自定义节点显示内容。
vue
<custom-tree :data="treeData" value-key="id" label-key="name">
<template #content="{ node, level, checked, indeterminate }">
<view class="custom-node">
<wd-icon :name="node.icon" size="18" />
<text :class="{ 'is-checked': checked }">{{ node.name }}</text>
<wd-tag v-if="node.type" size="small">{{ node.type }}</wd-tag>
</view>
</template>
</custom-tree>插槽参数:
| 参数 | 说明 | 类型 |
|---|---|---|
| node | 当前节点数据 | TreeOption |
| level | 节点层级(从 0 开始) | number |
| expanded | 是否展开 | boolean |
| selected | 是否选中(单选模式) | boolean |
| checked | 是否选中(多选模式) | boolean |
| indeterminate | 是否半选状态 | boolean |
自定义操作按钮
通过 action 插槽添加操作按钮,设置 show-action 显示默认操作按钮。
vue
<custom-tree :data="treeData" show-action>
<template #action="{ node, level }">
<wd-button size="small" @click.stop="handleEdit(node)">编辑</wd-button>
</template>
</custom-tree>自定义键名
通过 value-key、label-key、children-key 自定义数据字段映射。
vue
<custom-tree
:data="treeData"
value-key="id"
label-key="name"
children-key="children"
/>API
Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| data | 树形数据 | TreeOption[] | [] |
| value-key | 节点值的字段名 | string | 'value' |
| label-key | 节点标签的字段名 | string | 'label' |
| children-key | 子节点的字段名 | string | 'children' |
| default-expanded-keys | 默认展开的节点 | string[] | [] |
| default-selected-keys | 默认选中的节点(单选) | string[] | [] |
| selectable | 是否可单选 | boolean | false |
| default-expand-all | 是否默认展开所有节点 | boolean | false |
| show-action | 是否显示操作按钮区域 | boolean | false |
| checkable | 是否开启多选 | boolean | false |
| checked-keys | 选中的节点(多选) | string[] | [] |
| check-strictly | 父子节点是否不联动 | boolean | false |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| click | 点击节点时触发 | (node: TreeOption) |
| select | 单选选中时触发 | (node: TreeOption, selected: boolean) |
| expand | 展开/收起节点时触发 | (node: TreeOption, expanded: boolean) |
| action | 点击操作按钮时触发 | (node: TreeOption) |
| check | 多选选中变化时触发 | (checkedKeys: string[], info: { checked: boolean, node: TreeOption }) |
Slots
| 插槽名 | 说明 | 参数 |
|---|---|---|
| content | 自定义节点内容 | { node, level, expanded, selected, checked, indeterminate } |
| action | 自定义操作按钮 | { node, level } |
TreeOption 类型
typescript
interface TreeOption {
[key: string]: any // 其他自定义属性
value: string // 节点值(可通过 value-key 映射)
label: string // 节点标签(可通过 label-key 映射)
children?: TreeOption[] // 子节点(可通过 children-key 映射)
disabled?: boolean // 是否禁用
}完整示例
角色权限分配,核心是 checkable + checked-keys + #content 插槽:
vue
<script setup>
import { ref } from "vue"
import { onLoad } from "@dcloudio/uni-app"
const menuTree = ref([])
const checkedKeys = ref([])
function handleCheck(keys) {
checkedKeys.value = keys
}
onLoad(async () => {
// 并行加载菜单树和已选节点
const [menus, roleMenuIds] = await Promise.all([
MenuAPI.getList(),
RoleAPI.getRoleMenuIds(roleId),
])
menuTree.value = menus
checkedKeys.value = roleMenuIds.map(String)
})
</script>
<template>
<custom-tree
:data="menuTree"
:checkable="true"
:checked-keys="checkedKeys"
:default-expand-all="true"
value-key="id"
label-key="name"
@check="handleCheck"
>
<template #content="{ node, checked }">
<text :class="{ 'is-checked': checked }">{{ node.name }}</text>
</template>
</custom-tree>
</template>