Tree
用清晰的层级结构展示信息,可展开或折叠。
基础用法
基础的树形结构展示。
Level one 1
Level one 2
Level one 3
<template>
<mc-tree class="vp-raw" :data="data" @expand="() => {}" />
</template>
<script lang="ts" setup>
import type { TreeOption } from 'mealcomes';
const data: TreeOption[] = [
{
label: 'Level one 1',
key: '1',
children: [
{
label: 'Level two 1-1',
key: '11',
children: [
{
label: 'Level three 1-1-1',
key: '111'
}
]
}
]
},
{
label: 'Level one 2',
key: '2',
children: [
{
label: 'Level two 2-1',
key: '21',
children: [
{
label: 'Level three 2-1-1',
key: '211'
}
]
},
{
label: 'Level two 2-2',
key: '22',
children: [
{
label: 'Level three 2-2-1',
key: '221'
}
]
}
]
},
{
label: 'Level one 3',
key: '3',
children: [
{
label: 'Level two 3-1',
key: '31',
children: [
{
label: 'Level three 3-1-1',
key: '311'
}
]
},
{
label: 'Level two 3-2',
key: '32',
children: [
{
label: 'Level three 3-2-1',
key: '321'
}
]
}
]
}
];
</script>WARNING
传入的每个节点必须包含唯一的 key。
节点选择
节点可选择,通过设置 multiple 可进行多选(ctrl + 左键),也可通过 show-checkbox 显示复选框,default-checked-keys 可控制默认选中的复选框。
Level one 1
Level one 2
Level one 3
<template>
<div class="vp-raw">
<div class="buttons" style="margin-bottom: 1rem">
<mc-button @click="() => (multiple = !multiple)" size="small">
{{ multiple ? '切换为单选' : '切换为多选' }}
</mc-button>
<mc-button
@click="() => (showCheckbox = !showCheckbox)"
size="small"
>
{{ showCheckbox ? '隐藏复选框' : '展示复选框' }}
</mc-button>
</div>
<mc-tree
:data="data"
v-model:selected-keys="selectedKeys"
:default-checked-keys="checkedKeys"
selectable
:show-checkbox="showCheckbox"
:multiple="multiple"
@select="handleSelect"
@check="handleCheck"
></mc-tree>
</div>
</template>
<script setup lang="ts">
import type { CheckedInfo, SelectInfo, TreeKey, TreeOption } from 'mealcomes';
import { ref } from 'vue';
const selectedKeys = ref<TreeKey[]>([]);
const checkedKeys = ref<TreeKey[]>(['11', '2', '31']);
const multiple = ref(false);
const showCheckbox = ref(false);
const data: TreeOption[] = [
{
label: 'Level one 1',
key: '1',
children: [
{
label: 'Level two 1-1',
key: '11',
children: [
{
label: 'Level three 1-1-1',
key: '111'
}
]
}
]
},
{
label: 'Level one 2',
key: '2',
children: [
{
label: 'Level two 2-1',
key: '21',
children: [
{
label: 'Level three 2-1-1',
key: '211'
}
]
},
{
label: 'Level two 2-2',
key: '22',
children: [
{
label: 'Level three 2-2-1',
key: '221'
}
]
}
]
},
{
label: 'Level one 3',
key: '3',
children: [
{
label: 'Level two 3-1',
key: '31',
children: [
{
label: 'Level three 3-1-1',
key: '311'
}
]
},
{
label: 'Level two 3-2',
key: '32',
children: [
{
label: 'Level three 3-2-1',
key: '321'
}
]
}
]
}
];
const handleSelect = (target: TreeOption, selectInfo: SelectInfo) => {
console.log(target, selectInfo);
target.isLeaf = true;
};
const handleCheck = (target: TreeOption, checkInfo: CheckedInfo) => {
console.log(target, checkInfo);
target.isLeaf = true;
};
</script>节点展开控制
通过 v-model 双向绑定 expanded-keys 来控制节点的展开。
Level one 1
Level one 2
Level two 2-1
Level two 2-2
Level one 3
Level two 3-1
Level two 3-2
<template>
<mc-tree
class="vp-raw"
v-model:expanded-keys="expandedKeys"
:data="data"
@expand="handleExpand"
>
</mc-tree>
</template>
<script setup lang="ts">
import { ExpandInfo, TreeKey, TreeOption } from 'mealcomes';
import { ref } from 'vue';
const expandedKeys = ref<TreeKey[]>([2, 3]);
const data = [
{
key: 1,
label: 'Level one 1',
children: [
{
key: 4,
label: 'Level two 1-1',
children: [
{
key: 9,
label: 'Level three 1-1-1'
},
{
key: 10,
label: 'Level three 1-1-2'
}
]
}
]
},
{
key: 2,
label: 'Level one 2',
children: [
{
key: 5,
label: 'Level two 2-1'
},
{
key: 6,
label: 'Level two 2-2'
}
]
},
{
key: 3,
label: 'Level one 3',
children: [
{
key: 7,
label: 'Level two 3-1'
},
{
key: 8,
label: 'Level two 3-2'
}
]
}
];
const handleExpand = (target: TreeOption, expandInfo: ExpandInfo) => {
console.log(target, expandInfo);
};
</script>懒加载
点击展开节点,动态加载数据。
Out of Tao, One is bore
Out of Tao, One is bore
<template>
<mc-tree
class="vp-raw"
:load="loadNode"
:data="data"
@loaded="handleLoaded"
/>
</template>
<script lang="ts" setup>
import type { TreeOption } from 'mealcomes';
import { ref } from 'vue';
const data = ref(createDataAsync());
let cnt = 4;
function createDataAsync(): TreeOption[] {
return [
{
label: nextLabel(),
key: '1',
isLeaf: false
},
{
label: nextLabel(),
key: '2',
isLeaf: false
}
];
}
function nextLabel(currentLabel?: string | number | undefined): string {
if (!currentLabel) return 'Out of Tao, One is bore';
if (currentLabel === 'Out of Tao, One is bore') return 'Out of One, Two';
if (currentLabel === 'Out of One, Two') return 'Out of two, Tree';
if (currentLabel === 'Out of two, Tree')
return 'Out of tree, the create universe';
if (currentLabel === 'Out of tree, the create universe') {
return 'Out of Tao, One is born';
}
return '';
}
const loadNode = (node: TreeOption) => {
return new Promise<TreeOption[]>((res, rej) => {
setTimeout(() => {
if (cnt <= 0) rej();
cnt--;
res([
{
label: nextLabel(node.label),
key: `${node.key}-1`,
isLeaf: false
},
{
label: nextLabel(node.label),
key: `${node.key}-2`,
isLeaf: false
}
]);
}, 1000);
});
};
function handleLoaded(loadedData: TreeOption[]) {
console.log(loadedData);
}
</script>节点禁用
通过 disabled 设置节点的禁用状态。
Level one 1
<template>
<mc-tree class="vp-raw" :data="data" show-checkbox />
</template>
<script lang="ts" setup>
const data = [
{
key: 1,
label: 'Level one 1',
children: [
{
key: 3,
label: 'Level two 2-1',
children: [
{
key: 4,
label: 'Level three 3-1-1'
},
{
key: 5,
label: 'Level three 3-1-2',
disabled: true
}
]
},
{
key: 2,
label: 'Level two 2-2',
disabled: true,
children: [
{
key: 6,
label: 'Level three 3-2-1'
},
{
key: 7,
label: 'Level three 3-2-2',
disabled: true
}
]
}
]
}
];
</script>虚拟滚动
使用 height 属性则切换为虚拟滚动,从而实现大量数据的高性能树形展示。
node-1
node-2
node-3
node-4
node-5
node-6
node-7
node-8
<template>
<mc-tree class="vp-raw" :data="data" :height="100"> </mc-tree>
</template>
<script setup lang="ts">
const getKey = (prefix: string, id: number) => {
return `${prefix}-${id}`;
};
const createData = (
maxDeep: number,
maxChildren: number,
minNodesNumber: number,
deep = 1,
key = 'node'
) => {
let id = 0;
return Array.from({ length: minNodesNumber })
.fill(deep)
.map(() => {
const childrenNumber =
deep === maxDeep ? 0 : Math.round(Math.random() * maxChildren);
const nodeKey = getKey(key, ++id);
return {
key: nodeKey,
label: nodeKey,
children: childrenNumber
? createData(
maxDeep,
maxChildren,
childrenNumber,
deep + 1,
nodeKey
)
: undefined
};
});
};
const data = createData(4, 30, 40);
</script>自定义节点内容
packages
docs
<template>
<mc-tree class="vp-raw" :data="data" selectable>
<template #default="{ node }">
<mc-icon>
<component v-if="!node.isLeaf" :is="Folder" />
<component v-else :is="Document" />
</mc-icon>
<span class="custom-label">{{ node.label }}</span>
</template>
</mc-tree>
</template>
<script setup lang="ts">
import { Folder } from '@vicons/ionicons5';
import { Document } from '@vicons/ionicons5';
const data = [
{
label: 'packages',
key: '1',
children: [
{
label: 'src',
key: '11',
children: [
{
label: 'main.js',
key: '111',
isLeaf: true
},
{
label: 'App.vue',
key: '112',
isLeaf: true
}
]
},
{
label: 'package.json',
key: '12',
isLeaf: true
}
]
},
{
label: 'docs',
key: '2',
children: [
{
label: 'README.md',
key: '21',
isLeaf: true
}
]
}
];
</script>
<style scoped>
.custom-label {
margin-left: 6px;
font-weight: 500;
}
</style>API
Attributes
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| data | 展示数据 | object | - |
| labelField | 指定节点标签为节点对象的某个属性值 | string | label |
| keyField | 指定节点 key 为节点对象的某个属性值 | string | key |
| childrenField | 指定子树为节点对象的某个属性值 | string | children |
| expandedKeys (v-model) | 展开的节点的key数组 | Array<string | number> | - |
| selectable | 指定节点是否可选 | boolean | false |
| multiple | 指定节点是否可以多选 | boolean | false |
| selectedKeys (v-model) | 被选中的节点的 key 数组 | Array<string | number> | - |
| showCheckbox | 节点展示 checkbox 复选框 | boolean | false |
| defaultCheckedKeys | 默认 checkbox 被勾选的节点的 key 的数组 | Array<string | number> | - |
| load | 数据懒加载(设置即代表启用懒加载树) | (node) => Promise<TreeOption[]>> | - |
| height | 设置虚拟滚动容器高度 | number | - |
| item-size | 自定义树节点的高度(单位为像素) | number | 27 |
Events
| 事件名 | 说明 | 类型 |
|---|---|---|
| check | 点击复选框触发 | (target: TreeOption, checkInfo: CheckedInfo) => void |
| expand | 节点被展开或关闭时触发 | (target: TreeOption, expandInfo: ExpandInfo) => void |
| select | 节点被选择时触发 | (target: TreeOption, selectInfo: SelectInfo) => void |
| loaded | 异步加载成功时触发 | (loadedData: TreeOption[]) => void |
Slots
| 插槽名 | 说明 | 类型 |
|---|---|---|
| default | 自定义节点内容 | { node } |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| getCheckedKeys | 获取当前 checkbox 选中节点的 key 数组 | (leafOnly?: boolean) => Array<string | number> |
| getCheckedNodes | 获取当前 checkbox 选中节点的数组 | (leafOnly?: boolean) => TreeOption[] |
| getHalfCheckedKeys | 获取当前 checkbox 半选节点的 key 数组 | () => Array<string | number> |
| getHalfCheckedNodes | 获取当前 checkbox 半选节点的数组 | () => TreeOption[] |
| getSelectedKeys | 获取当前选中节点的 key 数组 | () => Array<string | number> |
| getSelectedNodes | 获取当前选中节点的数组 | () => TreeOption[] |
| getExpandedKeys | 获取当前展开节点的 key 数组 | () => Array<string | number> |
| getExpandedNodes | 获取当前展开节点的数组 | () => TreeOption[] |