介绍
用于显示层次结构数据,可展开或折叠。
代码演示
基础使用
通过 data 属性设置数据,通过 node-keys 属性告知如何从传入的数据中获取每个节点的数据。
<template>
<doc-page gray title="基础用法">
<s-tree :data="treeData" :node-keys="{ title: 'name', key: 'code' }" />
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script><template>
<doc-page gray title="基础用法">
<s-tree :data="treeData" :node-keys="{ title: 'name', key: 'code' }" />
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script>手风琴
对于同一级的节点,每次只能展开一个。
<template>
<doc-page gray title="手风琴">
<s-tree :data="treeData" :node-keys="{ title: 'name', key: 'code' }" accordion />
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script><template>
<doc-page gray title="手风琴">
<s-tree :data="treeData" :node-keys="{ title: 'name', key: 'code' }" accordion />
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script>可选择的
设置 selectable 属性可以显示复选框让用户选择节点,还可以禁用节点的选择。
节点的 key 属性是非常重要的(可以自定义 key 的键名),必须保证节点的 key 在所有节点中的唯一性。 如果没有设置 key,则由程序生成一个全局唯一的标识作为 key。
<template>
<doc-page gray title="可选择的">
<s-list>
<s-list-item hover arrow title="设置选中的节点" @click="setCheckedKeys" />
<s-list-item hover arrow title="获取选中的节点" @click="getCheckedKeys" />
<s-list-item hover arrow title="清空" @click="clear" />
</s-list>
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
selectable
default-expand-all
style="margin-top: 15px"
@check="(event) => console.log(event)"
/>
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
import { toast, type TreeExpose } from 'sard'
import { ref } from 'vue'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3),
})),
}))
const treeRef = ref<TreeExpose>()
const setCheckedKeys = () => {
treeRef.value?.setCheckedKeys([110101, 120100])
}
const getCheckedKeys = () => {
toast(treeRef.value?.getCheckedKeys().join(', '))
}
const clear = () => {
treeRef.value?.setCheckedKeys([])
}
</script><template>
<doc-page gray title="可选择的">
<s-list>
<s-list-item hover arrow title="设置选中的节点" @click="setCheckedKeys" />
<s-list-item hover arrow title="获取选中的节点" @click="getCheckedKeys" />
<s-list-item hover arrow title="清空" @click="clear" />
</s-list>
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
selectable
default-expand-all
style="margin-top: 15px"
@check="(event) => console.log(event)"
/>
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
import { toast } from 'sard'
import { ref } from 'vue'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3),
})),
}))
const treeRef = ref()
const setCheckedKeys = () => {
treeRef.value?.setCheckedKeys([110101, 120100])
}
const getCheckedKeys = () => {
toast(treeRef.value?.getCheckedKeys().join(', '))
}
const clear = () => {
treeRef.value?.setCheckedKeys([])
}
</script>严格选择
在显示复选框的情况下,设置 check-strictly 属性来严格遵循父子不互相关联规则。
<template>
<doc-page gray title="严格选择">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
selectable
check-strictly
/>
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script><template>
<doc-page gray title="严格选择">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
selectable
check-strictly
/>
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script>默认展开以及默认选中
树节点可以在初始化阶段被设置为展开和选中。
<template>
<doc-page gray title="默认展开以及默认选中">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
selectable
:default-checked-keys="defaultCheckedKeys"
:default-expanded-keys="defaultExpandedKeys"
/>
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
const defaultCheckedKeys = [110101, 120100]
const defaultExpandedKeys = [110101, 120100]
</script><template>
<doc-page gray title="默认展开以及默认选中">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
selectable
:default-checked-keys="defaultCheckedKeys"
:default-expanded-keys="defaultExpandedKeys"
/>
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
const defaultCheckedKeys = [110101, 120100]
const defaultExpandedKeys = [110101, 120100]
</script>单一选择
设置 single-selectable 属性即可实现单选,选择后会触发 select 事件,可使用 current 属性设置当前选择的节点。
<template>
<doc-page gray title="单一选择">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
v-model:current="value"
single-selectable
default-expand-all
style="margin-top: 15px"
@select="onSelect"
/>
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
import { type TreeStateNode } from 'sard'
import { ref } from 'vue'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3),
})),
}))
const value = ref(110102)
const onSelect = (key: number | string, node: TreeStateNode) => {
console.log(key, node)
}
</script><template>
<doc-page gray title="单一选择">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
v-model:current="value"
single-selectable
default-expand-all
style="margin-top: 15px"
@select="onSelect"
/>
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
import 'sard'
import { ref } from 'vue'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3).map((item, index) => ({
...item,
disabled: index === 0 ? true : false,
children: item.children.slice(0, 3),
})),
}))
const value = ref(110102)
const onSelect = (key, node) => {
console.log(key, node)
}
</script>仅选择叶子节点
设置 leaf-only 属性让其仅能选择叶子节点。
<template>
<doc-page gray title="仅选择叶子节点">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
single-selectable
leaf-only
default-expand-all
style="margin-top: 15px"
@select="onSelect"
/>
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
import { type TreeStateNode } from 'sard'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
const onSelect = (key: number | string, node: TreeStateNode) => {
console.log(key, node)
}
</script><template>
<doc-page gray title="仅选择叶子节点">
<s-tree
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
single-selectable
leaf-only
default-expand-all
style="margin-top: 15px"
@select="onSelect"
/>
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
import 'sard'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
const onSelect = (key, node) => {
console.log(key, node)
}
</script>可拖拽的
设置 draggable 属性使节点可拖拽,短按拖拽按钮便可进入拖拽状态; 单击拖拽按钮,还可以设置节点的层级。
<template>
<doc-page gray title="可拖拽的">
<s-tree :data="treeData" :node-keys="{ title: 'name', key: 'code' }" draggable />
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script><template>
<doc-page gray title="可拖拽的">
<s-tree :data="treeData" :node-keys="{ title: 'name', key: 'code' }" draggable />
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script>可编辑的
设置 editable 属性使节点可编辑(增删改),配合 draggable 属性便可以随意编辑树形数据。
<template>
<doc-page gray title="可编辑的">
<div class="flex m-3 gap-3 justify-center">
<s-button @click="addRootNode">添加根节点</s-button>
<s-button @click="getCleanTreeData">获取树形数据</s-button>
</div>
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
draggable
editable
/>
</doc-page>
</template>
<script setup lang="ts">
import { getRegionData } from 'region-data'
import { toast, type TreeExpose } from 'sard'
import { ref } from 'vue'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
const treeRef = ref<TreeExpose>()
const addRootNode = () => {
treeRef.value?.addRootNode()
}
const getCleanTreeData = () => {
toast('打开控制台查看')
console.log(treeRef.value?.getCleanTreeData())
}
</script><template>
<doc-page gray title="可编辑的">
<div class="flex m-3 gap-3 justify-center">
<s-button @click="addRootNode">添加根节点</s-button>
<s-button @click="getCleanTreeData">获取树形数据</s-button>
</div>
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
draggable
editable
/>
</doc-page>
</template>
<script setup lang="js">
import { getRegionData } from 'region-data'
import { toast } from 'sard'
import { ref } from 'vue'
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
const treeRef = ref()
const addRootNode = () => {
treeRef.value?.addRootNode()
}
const getCleanTreeData = () => {
toast('打开控制台查看')
console.log(treeRef.value?.getCleanTreeData())
}
</script>异步编辑与拖拽
使用 before-drop 和 before-edit 属性可在节点拖拽或编辑时与远程服务器通信,在接口请求失败时会取消拖拽和编辑。
这两属性也可用于同步阻止拖拽或编辑。
<template>
<doc-page gray title="异步编辑与拖拽">
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
draggable
editable
:before-edit="beforeEdit"
:before-drop="beforeDrop"
/>
</doc-page>
</template>
<script setup lang="ts">
import { sleep, type TreeProps } from 'sard'
import { getRegionData } from 'region-data'
import { toast, type TreeExpose } from 'sard'
import { ref } from 'vue'
// page
// tree
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
name: `${item.name} (编辑会失败)`,
children: item.children.slice(0, 3).map((item) => ({
...item,
name: `${item.name} (拖拽会失败)`,
children: item.children.slice(0, 3),
})),
}))
const treeRef = ref<TreeExpose>()
const beforeEdit: TreeProps['beforeEdit'] = async (node, title, type) => {
console.log(node, title, type)
// 模拟网络请求
await sleep(500)
if (type === 'edit' && /0{4}$/.test(String(node.key))) {
toast('编辑失败')
return Promise.reject()
}
}
const beforeDrop: TreeProps['beforeDrop'] = async (draggingNode, dropNode, type) => {
console.log(draggingNode, dropNode, type)
// 模拟网络请求
await sleep(500)
if (/[^0]0{2}$/.test(String(draggingNode.key))) {
toast('拖拽失败')
return Promise.reject()
}
}
</script><template>
<doc-page gray title="异步编辑与拖拽">
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
draggable
editable
:before-edit="beforeEdit"
:before-drop="beforeDrop"
/>
</doc-page>
</template>
<script setup lang="js">
import { sleep } from 'sard'
import { getRegionData } from 'region-data'
import { toast } from 'sard'
import { ref } from 'vue'
// page
// tree
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
name: `${item.name} (编辑会失败)`,
children: item.children.slice(0, 3).map((item) => ({
...item,
name: `${item.name} (拖拽会失败)`,
children: item.children.slice(0, 3),
})),
}))
const treeRef = ref()
const beforeEdit = async (node, title, type) => {
console.log(node, title, type)
// 模拟网络请求
await sleep(500)
if (type === 'edit' && /0{4}$/.test(String(node.key))) {
toast('编辑失败')
return Promise.reject()
}
}
const beforeDrop = async (draggingNode, dropNode, type) => {
console.log(draggingNode, dropNode, type)
// 模拟网络请求
await sleep(500)
if (/[^0]0{2}$/.test(String(draggingNode.key))) {
toast('拖拽失败')
return Promise.reject()
}
}
</script>树节点过滤
树节点是可以被过滤的。
调用 filter 方法来过滤树节点。方法的参数就是过滤关键字。 通过设置 filter-method 属性还可以实现自定义的过滤。
<template>
<doc-page gray title="树节点过滤">
<div style="padding: 16px; background: var(--s-bg-color-container)">
<s-input v-model="searchString" placeholder="请输入过滤关键词" />
</div>
<s-tree ref="treeRef" :data="treeData" :node-keys="{ title: 'name', key: 'code' }" />
</doc-page>
</template>
<script setup lang="ts">
import { type TreeExpose } from 'sard'
import { ref, watch } from 'vue'
import { getRegionData } from 'region-data'
const searchString = ref('')
const treeRef = ref<TreeExpose>()
watch(searchString, () => {
treeRef.value?.filter(searchString.value)
})
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script><template>
<doc-page gray title="树节点过滤">
<div style="padding: 16px; background: var(--s-bg-color-container)">
<s-input v-model="searchString" placeholder="请输入过滤关键词" />
</div>
<s-tree ref="treeRef" :data="treeData" :node-keys="{ title: 'name', key: 'code' }" />
</doc-page>
</template>
<script setup lang="js">
import 'sard'
import { ref, watch } from 'vue'
import { getRegionData } from 'region-data'
const searchString = ref('')
const treeRef = ref()
watch(searchString, () => {
treeRef.value?.filter(searchString.value)
})
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script>严格的树节点过滤
默认的过滤是宽松的,即匹配到一个节点后便停止后代节点的匹配,其后代节点都会被显示出来。
设置 filter-mode="strict" 进入严格模式,即所有节点都要进行匹配,只有匹配成功的节点才会显示出来。
<template>
<doc-page gray title="严格的树节点过滤">
<div style="padding: 16px; background: var(--s-bg-color-container)">
<s-input v-model="searchString" placeholder="请输入过滤关键词" />
</div>
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
filter-mode="strict"
/>
</doc-page>
</template>
<script setup lang="ts">
import { type TreeExpose } from 'sard'
import { ref, watch } from 'vue'
import { getRegionData } from 'region-data'
const searchString = ref('')
const treeRef = ref<TreeExpose>()
watch(searchString, () => {
treeRef.value?.filter(searchString.value)
})
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script><template>
<doc-page gray title="严格的树节点过滤">
<div style="padding: 16px; background: var(--s-bg-color-container)">
<s-input v-model="searchString" placeholder="请输入过滤关键词" />
</div>
<s-tree
ref="treeRef"
:data="treeData"
:node-keys="{ title: 'name', key: 'code' }"
filter-mode="strict"
/>
</doc-page>
</template>
<script setup lang="js">
import 'sard'
import { ref, watch } from 'vue'
import { getRegionData } from 'region-data'
const searchString = ref('')
const treeRef = ref()
watch(searchString, () => {
treeRef.value?.filter(searchString.value)
})
const regionData = getRegionData()
const treeData = regionData.slice(0, 5).map((item) => ({
...item,
children: item.children.slice(0, 3).map((item) => ({
...item,
children: item.children.slice(0, 3),
})),
}))
</script>懒加载
设置 lazy 属性标识为懒加载,设置 load 属性用于获取数据,会在点击节点时调用,当获取的数据为空时,会将点击的节点标识为叶子节点,并隐藏箭头按钮。当然,你也可以提前设置节点是否为叶子节点,以避免为叶子节点时渲染箭头按钮。
<template>
<doc-page gray title="懒加载">
<s-tree
lazy
:load="loadNode"
:node-keys="{ title: 'name', key: 'code', isLeaf: 'leaf' }"
selectable
/>
</doc-page>
</template>
<script setup lang="ts">
import { mapProvinces, mapCities, mapCounties } from 'region-data'
import { type TreeStateNode } from 'sard'
const doGetTreeData = (parentId?: number) => {
if (!parentId) {
return Object.entries(mapProvinces).map(([code, name]) => ({
code: +code,
name,
isLeaf: false,
}))
} else {
const isProvince = /^\d{2}0{4}/.test(String(parentId))
const isCity = !isProvince && /^\d{4}0{2}/.test(String(parentId))
const prefixCode = isProvince
? String(parentId).slice(0, 2)
: isCity
? String(parentId).slice(0, 4)
: ''
const map = isProvince ? mapCities : isCity ? mapCounties : {}
return Object.entries(map)
.filter(([code]) => String(code).startsWith(prefixCode))
.map(([code, name]) => ({
code: +code,
name,
isLeaf: isCity,
}))
}
}
const getTreeData = (parentId?: number) => {
return new Promise<ReturnType<typeof doGetTreeData>>((resolve) => {
setTimeout(() => {
const treeData = doGetTreeData(parentId)
resolve(treeData)
}, 500)
})
}
const loadNode = async (node?: TreeStateNode) => {
const treeData = await getTreeData(node?.key as number)
return treeData.map((item) => ({
...item,
leaf: node?.depth === 1,
}))
}
</script><template>
<doc-page gray title="懒加载">
<s-tree
lazy
:load="loadNode"
:node-keys="{ title: 'name', key: 'code', isLeaf: 'leaf' }"
selectable
/>
</doc-page>
</template>
<script setup lang="js">
import { mapProvinces, mapCities, mapCounties } from 'region-data'
import 'sard'
const doGetTreeData = (parentId) => {
if (!parentId) {
return Object.entries(mapProvinces).map(([code, name]) => ({
code: +code,
name,
isLeaf: false,
}))
} else {
const isProvince = /^\d{2}0{4}/.test(String(parentId))
const isCity = !isProvince && /^\d{4}0{2}/.test(String(parentId))
const prefixCode = isProvince
? String(parentId).slice(0, 2)
: isCity
? String(parentId).slice(0, 4)
: ''
const map = isProvince ? mapCities : isCity ? mapCounties : {}
return Object.entries(map)
.filter(([code]) => String(code).startsWith(prefixCode))
.map(([code, name]) => ({
code: +code,
name,
isLeaf: isCity,
}))
}
}
const getTreeData = (parentId) => {
return new Promise((resolve) => {
setTimeout(() => {
const treeData = doGetTreeData(parentId)
resolve(treeData)
}, 500)
})
}
const loadNode = async (node) => {
const treeData = await getTreeData(node?.key)
return treeData.map((item) => ({
...item,
leaf: node?.depth === 1,
}))
}
</script>API
TreeProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| data | 树形数据 | TreeNaturalNode[] | - |
| node-keys | 节点对象的键名 | TreeNodeKeys | defaultNodeKeys |
| default-expand-all | 是否默认展开所有节点 | boolean | false |
| default-expanded-keys | 默认展开的节点的 key | (string | number)[] | - |
| accordion | 是否每次只展示一个同级树节点 | boolean | false |
| selectable | 节点是否可被选择(复选) | boolean | false |
| check-strictly | 可选时是否严格遵循父子不关联的做法(复选) | boolean | false |
| default-checked-keys | 默认勾选的节点的 key 的数组(复选) | (string | number)[] | - |
| single-selectable | 节点是否可被选择(单选) | boolean | false |
| leaf-only | 是否只能选择叶子节点(单选) | boolean | false |
| current | 当前选择的节点的 key(单选) | string | number | - |
| draggable | 是否可以拖拽节点 | boolean | false |
| editable | 是否可编辑节点(增删改) | boolean | false |
| filter-mode | 节点过滤模式 | 'lenient' | 'strict' | 'lenient' |
| filter-method | 自定义过滤方法 | (value: string, node: TreeStateNode) => boolean | - |
| lazy | 是否懒加载子节点,需与 load 方法结合使用 | boolean | false |
| load | 加载子树数据的方法,仅当 lazy 属性为true 时生效 | (node?: TreeStateNode) => Promise<TreeNaturalNode[]> | TreeNaturalNode[] | - |
| auto-height | 默认只可展示一行文字,设置此属性可让节点高度跟随内容变化,只可用在非拖拽模式 | boolean | false |
| allow-drag | 判断节点能否被拖拽,返回 false 不允许拖拽 | (node: TreeStateNode) => boolean | - |
| before-drop | 拖拽完放置前回调,返回 false 或 Promise{<rejected>} 可阻止放置 | (draggingNode: TreeStateNode, dropNode: TreeStateNode, type: TreeDropType) => any | Promise\<any> | - |
| before-edit | 节点编辑前回调,返回 false 或 Promise{<rejected>} 可阻止编辑 | (node: TreeStateNode, title: string, type: TreeEditType) => any | Promise \<any> | - |
TreeEmits
| 事件 | 描述 | 类型 |
|---|---|---|
| update:current | 选择节点后触发(单选) | (key: string | number, node: TreeStateNode) => void |
| select | 选择节点后触发(单选) | (key: string | number, node: TreeStateNode) => void |
| check | 点击树节点复选框时触发 | (event: {checked: boolean; node: TreeStateNode}) => void |
| node-click | 点击树节点时触发 | (event: {event: any; node: TreeStateNode}) => void |
TreeExpose
| 属性 | 描述 | 类型 |
|---|---|---|
| setExpanded | 设置节点是否展开 | (key: string | number, expanded: boolean) => void |
| toggleExpanded | 切换节点展开状态 | (key: string | number) => void |
| setExpandedKeys | 设置指定节点为展开状态 | (keys: (string | number)[]) => void |
| getExpandedKeys | 获取展开状态的节点 | (keys: (string | number)[]) => void |
| getCheckedKeys | 获取所有选中节点的 key | () => (string | number)[] |
| getHalfCheckedKeys | 获取所有半选节点的 key | () => (string | number)[] |
| setCheckedKeys | 设置指定节点为选中状态 | (keys: (string | number)[]) => void |
| setChecked | 设置节点是否选中 | (key: string | number, checked: boolean) => void |
| addRootNode | 添加根节点 | () => void |
| getCleanTreeData | 获取干净的当前树形数据 | () => TreeCleanNode[] |
| filter | 过滤树节点 | (searchString: string) => void |
TreeDropType
type TreeDropType = 'before' | 'after' | 'prepend' | 'append'TreeEditType
type TreeEditType = 'addSibling' | 'addChild' | 'addRoot' | 'edit' | 'delete'TreeNaturalNode
interface TreeNaturalNode {
title?: string | number
key?: any
children?: TreeNaturalNode[]
disabled?: boolean
isLeaf?: boolean
[prop: string]: any
}TreeCleanNode
interface TreeCleanNode {
title: string | number
key: string | number
children?: TreeCleanNode[]
}TreeStateNode
export interface TreeStateNode {
title: string | number
key: string | number
expanded: boolean
checked: boolean
children?: TreeStateNode[]
parent: TreeStateNode | null
indeterminate: boolean
level: number
offsetLevel: number
visible: boolean
disabled: boolean
isLeaf: boolean
loadStatus: 'idle' | 'loading' | 'loaded'
depth: number
}TreeNodeKeys
interface TreeNodeKeys {
title?: string
key?: string
children?: string
isLeaf?: string
}defaultNodeKeys
const defaultNodeKeys = {
title: 'title',
key: 'key',
children: 'children',
isLeaf: 'isLeaf',
}const defaultNodeKeys = {
title: 'title',
key: 'key',
children: 'children',
isLeaf: 'isLeaf',
}主题定制
样式变量
| CSS 变量 | 值 |
|---|---|
--s-tree-border-color | var(--s-border-color) |
--s-tree-bg | var(--s-bg-color-container) |
--s-tree-loading-size | var(--s-font-size) |
--s-tree-loading-color | var(--s-text-color-fourth) |
--s-tree-loading-margin-y | 10px |
--s-tree-node-height | var(--s-content-height-sm) |
--s-tree-node-padding-x | var(--s-content-padding-x) |
--s-tree-node-padding-y | var(--s-content-padding-y) |
--s-tree-node-bg | var(--s-bg-color-container) |
--s-tree-node-bg-active | var(--s-bg-color-active) |
--s-tree-node-box-shadow-dragging | var(--s-box-shadow-secondary) |
--s-tree-node-loading-margin-end | var(--s-size-xs) |
--s-tree-toolbar-margin-end | -12px |
--s-tree-indent-width | var(--s-size-xl) |
--s-tree-arrow-padding-x | var(--s-size-sm) |
--s-tree-arrow-font-size | var(--s-font-size-sm) |
--s-tree-arrow-color | var(--s-text-color-tertiary) |
--s-tree-selection-padding-x | var(--s-size-sm) |
--s-tree-edit-padding-x | var(--s-size-sm) |
--s-tree-edit-font-size | 18px |
--s-tree-edit-color | var(--s-text-color-fourth) |
--s-tree-edit-opacity-active | var(--s-opacity-active) |
--s-tree-level-btn-padding-x | var(--s-size-sm) |
--s-tree-level-btn-font-size | 18px |
--s-tree-level-btn-color | var(--s-text-color-fourth) |
--s-tree-level-btn-opacity-active | var(--s-opacity-active) |
--s-tree-drag-padding-x | var(--s-size-sm) |
--s-tree-drag-font-size | 18px |
--s-tree-drag-color | var(--s-text-color-fourth) |
--s-tree-drag-opacity-active | var(--s-opacity-active) |