使用场景
当需要选择的选项为树形结构时,可以使用树选择器,例如部门层级、学科体系、分类目录等。
代码演示
如何引入
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
</script>
基本用法
最简单的用法,默认为单选模式,每一级菜单项均可选择。
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
const style = { width: '300px' };
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
</script>
<template>
<TreeSelect :dropdownStyle="dropdownStyle" placeholder="请选择" :style="style" :treeData="treeData" />
</template>多选
设置 multiple,可以进行多选。多选情况下所有子项都被选择时,自动勾选显示其父项。
多选时 v-model 与 defaultValue 都是数组。通过 leafOnly 属性,可以设置只展示叶子节点,同时 v-model 的值与 change 事件的值也只有叶子节点的值。
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
{
label: 'Chengdu',
value: 'Chengdu',
key: '0-0-2',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
</script>
<template>
<div>
<TreeSelect :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" multiple placeholder="请选择" style="width: 300px" :treeData="treeData" />
<br />
<br />
<TreeSelect :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" leafOnly multiple placeholder="只渲染叶子节点" style="width: 300px" :treeData="treeData" />
<br />
<br />
</div>
</template>限制标签展示数量
在多选的场景中,利用 maxTagCount 可以限制展示的标签数量,超出部分将以 +N 的方式展示。
使用 showRestTagsPopover (>= v2.22.0) 可以设置在超出 maxTagCount 后,hover +N 是否显示 Popover,默认为 false。并且,还可以在 restTagsPopoverProps 属性中配置 Popover。
maxTagCount=2:
maxTagCount=2, showRestTagsPopover:
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
{
label: 'Chengdu',
value: 'Chengdu',
key: '0-0-2',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
const textStyle = { margin: '20px 0 10px' };
</script>
<template>
<div>
<h4 :style="textStyle">maxTagCount=2:</h4>
<TreeSelect :defaultValue="['Beijing', 'Chengdu', 'Canada']" :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" :maxTagCount="2" multiple placeholder="当选中标签超过两个将折叠" style="width: 300px" :treeData="treeData" />
<h4 :style="textStyle">maxTagCount=2, showRestTagsPopover:</h4>
<TreeSelect :defaultValue="['Beijing', 'Chengdu', 'Canada']" :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" :maxTagCount="2" multiple placeholder="hover +N 查看" :restTagsPopoverProps="{ position: 'top' }" showRestTagsPopover style="width: 300px" :treeData="treeData" />
</div>
</template>可搜索的
通过设置 filterTreeNode 属性可支持搜索功能。默认对 label 值进行搜索,可通过 treeNodeFilterProp 更改。
如果只希望展示过滤后的结果,可以设置 showFilteredOnly 。
如果想要获取搜索结果的具体信息,可监听 search 事件,事件参数见 API 列表。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Switch, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const showFilteredOnly = ref(false);
const treeData: TreeNodeData[] = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{ label: 'Beijing', value: 'Beijing', key: '0-0-0' },
{ label: 'Shanghai', value: 'Shanghai', key: '0-0-1' },
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [{ label: 'Osaka', value: 'Osaka', key: '0-1-0' }],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{ label: 'United States', value: 'United States', key: '1-0' },
{ label: 'Canada', value: 'Canada', key: '1-1' },
],
},
];
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
function onSearch(inputValue: string, filteredExpandedKeys: string[], filteredNodes: TreeNodeData[]) {
console.log('onSearch', inputValue, filteredExpandedKeys, filteredNodes);
}
</script>
<template>
<span id="treeselect-searchable-filtered-only">showFilteredOnly</span>
<Switch v-model="showFilteredOnly" aria-labelledby="treeselect-searchable-filtered-only" size="small" />
<br />
<br />
<TreeSelect :dropdownStyle="dropdownStyle" filterTreeNode placeholder="单选可搜索的" :showFilteredOnly="showFilteredOnly" style="width: 300px" :treeData="treeData" @search="onSearch" />
<br />
<br />
<TreeSelect :dropdownStyle="dropdownStyle" filterTreeNode :maxTagCount="2" multiple placeholder="多选可搜索的" searchPlaceholder="请输入关键字开始搜索" :showFilteredOnly="showFilteredOnly" style="width: 300px" :treeData="treeData" @search="onSearch" />
<br />
<br />
<TreeSelect :dropdownStyle="dropdownStyle" filterTreeNode :maxTagCount="2" multiple placeholder="搜索框autofocus" searchAutoFocus searchPlaceholder="autofocus" :showFilteredOnly="showFilteredOnly" style="width: 300px" :treeData="treeData" @search="onSearch" />
</template>远程搜索
通过设置 remote 属性可启用远程搜索。开启后,输入时不会执行本地过滤,而是仅触发 search 事件,用户可自行处理远程数据获取并更新 treeData(传入新数组才会更新)。
代码
<script setup lang="ts">
import { ref, shallowRef } from 'vue';
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const value = ref<string>();
const treeData = shallowRef<TreeNodeData[]>([]);
function onSearch(inputValue: string) {
if (!inputValue) {
treeData.value = [];
return;
}
setTimeout(() => {
treeData.value = [
{ label: `${inputValue} - 结果1`, value: `${inputValue}-1`, key: `${inputValue}-1` },
{ label: `${inputValue} - 结果2`, value: `${inputValue}-2`, key: `${inputValue}-2` },
{ label: `${inputValue} - 结果3`, value: `${inputValue}-3`, key: `${inputValue}-3` },
];
}, 500);
}
</script>
<template>
<TreeSelect v-model="value" filterTreeNode placeholder="请输入关键字进行远程搜索" remote style="width: 300px" :treeData="treeData" @search="onSearch" />
</template>搜索框位置
可以使用 searchPosition 来设置搜索框的位置,可选: dropdown(默认)、trigger。
当输入框位于 trigger 时:
- 搜索框占位符由
placeholder控制; showClear=true时,点击输入框的清空按钮,将同时清空 inputValue 和 value。
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{
label: 'Beijing',
value: 'Beijing',
key: '0-0-0',
},
{
label: 'Shanghai',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [
{
label: 'Osaka',
value: 'Osaka',
key: '0-1-0',
},
],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{
label: 'United States',
value: 'United States',
key: '1-0',
},
{
label: 'Canada',
value: 'Canada',
key: '1-1',
},
],
},
];
</script>
<template>
<TreeSelect :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" filterTreeNode placeholder="单选" searchPosition="trigger" style="width: 300px" :treeData="treeData" />
<br />
<br />
<TreeSelect :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" filterTreeNode :maxTagCount="2" multiple placeholder="多选" searchPosition="trigger" style="width: 300px" :treeData="treeData" />
</template>Trigger 内多行换行(triggerTagWrap)
当你在 多选 + 搜索框位于 trigger 的场景下,选择了较多项或输入较长文本时,默认 trigger 可能会更倾向于保持单行展示。
开启 triggerTagWrap 后,可以让 trigger 内的已选标签支持自动换行(多行展示)。
代码
<script setup lang="ts">
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const treeData: TreeNodeData[] = [
{
label: 'Asia',
value: 'Asia',
key: '0',
children: [
{
label: 'China',
value: 'China',
key: '0-0',
children: [
{ label: 'Beijing', value: 'Beijing', key: '0-0-0' },
{ label: 'Shanghai', value: 'Shanghai', key: '0-0-1' },
{ label: 'Shenzhen', value: 'Shenzhen', key: '0-0-2' },
{ label: 'Guangzhou', value: 'Guangzhou', key: '0-0-3' },
],
},
{
label: 'Japan',
value: 'Japan',
key: '0-1',
children: [{ label: 'Osaka', value: 'Osaka', key: '0-1-0' }],
},
],
},
{
label: 'North America',
value: 'North America',
key: '1',
children: [
{ label: 'United States', value: 'United States', key: '1-0' },
{ label: 'Canada', value: 'Canada', key: '1-1' },
],
},
];
const defaultValue = ['Beijing', 'Shanghai', 'Shenzhen', 'Guangzhou'];
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
</script>
<template>
<TreeSelect :defaultValue="defaultValue" :dropdownStyle="dropdownStyle" filterTreeNode multiple placeholder="请选择多个选项或输入长文本" searchPosition="trigger" style="width: 260px" :treeData="treeData" triggerTagWrap />
</template>尺寸大小
可以通过 size 设置尺寸大小,可选: 'small'、'default'、'large'
代码
<script setup lang="ts">
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const treeData: TreeNodeData[] = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{ label: '北京', value: 'Beijing', key: '0-0-0' },
{ label: '上海', value: 'Shanghai', key: '0-0-1' },
],
},
],
},
{ label: '北美洲', value: 'North America', key: '1' },
];
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
</script>
<template>
<div>
<TreeSelect :dropdownStyle="dropdownStyle" multiple placeholder="small" size="small" style="width: 300px" :treeData="treeData" />
<br />
<br />
<TreeSelect :dropdownStyle="dropdownStyle" multiple placeholder="default" size="default" style="width: 300px" :treeData="treeData" />
<br />
<br />
<TreeSelect :dropdownStyle="dropdownStyle" multiple placeholder="large" size="large" style="width: 300px" :treeData="treeData" />
</div>
</template>默认展开
defaultExpandAll 和 expandAll 均可以设置 TreeSelect 的默认展开/收起状态。二者的区别是,defaultExpandAll 只在初始化时生效,而 expandAll 不仅会在初始化时生效,当数据(treeData)发生动态更新时,expandAll 也仍然生效。
在下面的 demo 中,TreeData 更新后,defaultExpandAll 失效,expandAll 仍然生效。
代码
<script setup lang="ts">
import { onBeforeUnmount, onMounted, shallowRef } from 'vue';
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const source: TreeNodeData[] = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
const firstStyle = { width: '300px', marginBottom: '20px' };
const secondStyle = { width: '300px' };
const data = shallowRef<TreeNodeData[]>([]);
let timer: ReturnType<typeof setTimeout> | undefined;
onMounted(() => {
timer = setTimeout(() => {
data.value = source;
}, 500);
});
onBeforeUnmount(() => clearTimeout(timer));
</script>
<template>
<TreeSelect expandAll placeholder="expandAll" :style="firstStyle" :treeData="data" />
<TreeSelect defaultExpandAll placeholder="defaultExpandAll" :style="secondStyle" :treeData="data" />
</template>禁用
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
const style = { width: '300px' };
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
</script>
<template>
<div>
<TreeSelect disabled :dropdownStyle="dropdownStyle" placeholder="禁用下拉菜单" :style="style" :treeData="treeData" />
<br />
<br />
<TreeSelect defaultValue="Shanghai" disabled :dropdownStyle="dropdownStyle" :style="style" :treeData="treeData" />
<br />
<br />
<TreeSelect :defaultValue="['Shanghai', 'North America']" disabled :dropdownStyle="dropdownStyle" multiple :style="style" :treeData="treeData" />
</div>
</template>严格禁用
可以使用 disableStrictly 来开启严格禁用。开启严格禁用后,当节点是 disabled 的时候,则不能通过子级或者父级的关系改变选中状态。
以下面的 demo 为例,节点"中国"开启了严格禁用,因此,当我们改变其父节点"亚洲"的选中状态时,也不会影响到节点"中国"的选中状态。
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
disabled: true,
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: '日本',
value: 'Japan',
key: '0-1',
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
const style = { width: '300px' };
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
</script>
<template>
<div>
<TreeSelect :defaultValue="['Shanghai']" disableStrictly :dropdownStyle="dropdownStyle" multiple :style="style" :treeData="treeData" />
</div>
</template>受控
使用 v-model 绑定选中值即为受控组件,选中值变化时通过 update:modelValue 回写;也可以传入 modelValue 并监听 change 事件。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
const style = { width: '300px' };
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
const value = ref<string | undefined>('Shanghai');
</script>
<template>
<TreeSelect v-model="value" :dropdownStyle="dropdownStyle" placeholder="请选择" :style="style" :treeData="treeData" />
</template>节点选中关系
版本:>= 2.5.0
多选时,可以使用 checkRelation 来设置节点之间选中关系的类型,可选:'related'(默认)、'unRelated'。当选中关系为 'unRelated' 时,意味着节点之间的选中互不影响。
代码
<script setup lang="ts">
import { TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
const style = { width: '300px' };
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
</script>
<template>
<TreeSelect checkRelation="unRelated" :defaultValue="['Asia']" :dropdownStyle="dropdownStyle" multiple :style="style" :treeData="treeData" />
</template>开启搜索的展开受控
使用 v-model:expandedKeys 绑定展开的节点即为展开受控组件,也可以传入 expandedKeys 并监听 expand 事件。当展开受控时,如果开启 filterTreeNode 并进行搜索是不会再自动展开节点的,此时,节点的展开完全由 expandedKeys 来控制。你可以利用 search 事件的参数 filteredExpandedKeys 来实现展开受控时的搜索展开效果。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from '@fibrous/semi-ui-vue';
const expandedKeys = ref<string[]>([]);
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
{
label: '日本',
value: 'Japan',
key: '0-1',
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
];
function onSearch(_inputValue: string, filteredExpandedKeys: string[]) {
expandedKeys.value = [...filteredExpandedKeys, ...expandedKeys.value];
}
</script>
<template>
<TreeSelect v-model:expandedKeys="expandedKeys" :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" filterTreeNode style="width: 300px" :treeData="treeData" @search="onSearch" />
</template>虚拟化
列表虚拟化,用于大量树节点的情况。开启后,动画效果将被关闭。
virtualize 是一个包含下列值的对象:
- height: 高度值,如果为 string 必须有计算高度才能被渲染出来,即其父节点有 offsetHeight。建议传入数值。
- width: 宽度值,默认 100%
- itemSize: 每行的treeNode的高度,必传
如果带搜索框,建议开启 showFilteredOnly 减少多余节点的渲染。
代码
<script setup lang="ts">
import { ref, shallowRef } from 'vue';
import { Button, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const treeData = shallowRef<TreeNodeData[]>([]);
const total = ref(0);
// x: nodes per level. y: nodes with children per level. z: depth (0 is one level).
function generateData(x = 5, y = 4, z = 3) {
const data: TreeNodeData[] = [];
function fill(level: number, preKey: string, nodes: TreeNodeData[]) {
const parents: string[] = [];
for (let i = 0; i < x; i++) {
const key = `${preKey}-${i}`;
nodes.push({ label: `${key}-标签`, key: `${key}-key`, value: `${key}-value` });
if (i < y) {
parents.push(key);
}
}
if (level < 0) {
return;
}
parents.forEach((key, index) => {
const children: TreeNodeData[] = [];
nodes[index].children = children;
fill(level - 1, key, children);
});
}
fill(z, '0', data);
let count = 0;
for (let n = z + 1; n >= 0; n--) {
count += x * y ** n;
}
return { data, count };
}
function onGen() {
const { data, count } = generateData();
treeData.value = data;
total.value = count;
}
const dropdownStyle = { overflow: 'hidden' };
// Dropdown height 300 minus the search box, minus the 8 * 2 padding; a set dropdown height fills the remaining space.
const virtualize = { itemSize: 28, height: 236 };
</script>
<template>
<div style="padding: 0 20px">
<Button @click="onGen">生成数据: </Button>
<span>共 {{ total }} 个节点</span>
<br />
<br />
<TreeSelect v-if="treeData.length" :dropdownStyle="dropdownStyle" filterTreeNode placeholder="Please select" showFilteredOnly style="width: 300px" :treeData="treeData" :virtualize="virtualize" />
</div>
</template>动态更新数据
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { Button, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const style = { width: '300px' };
const dropdownStyle = { maxHeight: '400px', overflow: 'auto' };
const treeData = shallowRef<TreeNodeData[]>([]);
function add() {
const itemLength = Math.floor(Math.random() * 5) + 1;
treeData.value = Array.from({ length: itemLength }, (_, i) => {
const length = Math.floor(Math.random() * 3);
const children = Array.from({ length }, (_, ci) => ({
key: `${i}-${ci}`,
label: `Leaf-${i}-${ci}`,
value: `${i}-${ci}`,
}));
return {
key: `${i}`,
label: `Item-${i}`,
value: `${i}`,
children,
};
});
}
</script>
<template>
<TreeSelect :dropdownStyle="dropdownStyle" placeholder="请选择" :style="style" :treeData="treeData" />
<br />
<br />
<Button @click="add">动态改变数据</Button>
</template>异步加载数据
通过设置 loadData 可以动态加载数据,此时需要在数据中传入 isLeaf 标明叶子节点。
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const treeData = shallowRef<TreeNodeData[]>([
{
label: 'Expand to load',
value: '0',
key: '0',
},
{
label: 'Expand to load',
value: '1',
key: '1',
},
{
label: 'Leaf Node',
value: '2',
key: '2',
isLeaf: true,
},
]);
function updateTreeData(list: TreeNodeData[], key: string | undefined, children: TreeNodeData[]): TreeNodeData[] {
return list.map((node) => {
if (node.key === key) {
return { ...node, children };
}
if (node.children) {
return { ...node, children: updateTreeData(node.children, key, children) };
}
return node;
});
}
function loadData({ key, children }: TreeNodeData) {
return new Promise<void>((resolve) => {
if (children) {
resolve();
return;
}
setTimeout(() => {
treeData.value = updateTreeData(treeData.value, key, [
{
label: 'Child Node',
key: `${key}-0`,
},
{
label: 'Child Node',
key: `${key}-1`,
},
]);
resolve();
}, 1000);
});
}
</script>
<template>
<TreeSelect :loadData="loadData" placeholder="请选择" style="width: 300px" :treeData="treeData" />
</template>自定义 Trigger
如果默认的触发器样式满足不了你的需求,可以用 #trigger 插槽自定义选择框的展示。
#trigger 的插槽参数如下,类型为 TreeSelectTriggerSlotProps:
interface TreeSelectTriggerSlotProps {
componentProps: TreeSelectProps; // 所有用户传给 TreeSelect 的 props
disabled: boolean; // 是否禁用 TreeSelect
value: TreeNodeData[]; // 已选中的 node 的数据
inputValue: string; // 当前 input 框的输入值
placeholder?: string; // placeholder
// 用于清空值的函数;绑定在触发器内的控件上时传入点击事件,避免这次点击同时打开下拉
onClear: (event?: MouseEvent) => void;
// 删除单个 item 时调用的函数,以 item 的 key 作为入参
onRemove: (key: string) => void;
// 用于在 Input 框值更新时启动搜索,需要设置 filterTreeNode 非 false,
// searchPosition 为 'trigger'
onSearch: (inputValue: string) => void;
}
代码
<script setup lang="ts">
import { Tag, TagInput, TreeSelect, type TreeNodeData } from '@fibrous/semi-ui-vue';
const treeData: TreeNodeData[] = [
{
label: '亚洲',
value: '亚洲',
key: '0',
children: [
{
label: '中国',
value: '中国',
key: '0-0',
children: [
{ label: '北京', value: '北京', key: '0-0-0' },
{ label: '上海', value: '上海', key: '0-0-1' },
],
},
],
},
{ label: '北美洲', value: '北美洲', key: '1' },
];
function onChange(value: unknown) {
console.log('onChange', value);
}
</script>
<template>
<TreeSelect filterTreeNode multiple placeholder="Custom Trigger" searchPosition="trigger" style="width: 300px" :treeData="treeData" @change="onChange">
<template #trigger="{ value, inputValue, onSearch, onRemove }">
<TagInput :inputValue="inputValue" :modelValue="value.flatMap((item) => item.key ?? [])" @inputChange="onSearch">
<template #tag="{ value: key }">
<Tag :key="key" closable style="margin-inline-start: 2px" :tagKey="key" @close="onRemove(key)">
{{ value.find((item) => item.key === key)?.label }}
</Tag>
</template>
</TagInput>
</template>
</TreeSelect>
</template>自定义渲染已选项
你可以通过 #selectedItem 和 #tag 插槽自定义选择框中已选项的渲染结构,两个插槽的参数相同,类型为 TreeSelectSelectedItemSlotProps:item(节点数据)、index、disabled 和 onClose(移除该标签,单选时清除选中值)。
- 单选时
#selectedItem的内容就是选择框中显示的内容;内容为空时显示placeholder - 多选时
#selectedItem的内容会放进内置的 Tag 中渲染(带有背景色以及关闭按钮);#tag替换整个 Tag,优先于#selectedItem,需要关闭按钮时把onClose绑定到自己的 Tag 上 - 多选时两个插槽的内容为空,都不渲染该标签
单选
多选 + 标签内渲染
多选 + 替换整个标签
代码
<script setup lang="ts">
import { Tag, TreeSelect } from '@fibrous/semi-ui-vue';
const treeData = [
{
label: '亚洲',
value: 'Asia',
key: '0',
children: [
{
label: '中国',
value: 'China',
key: '0-0',
children: [
{
label: '北京',
value: 'Beijing',
key: '0-0-0',
},
{
label: '上海',
value: 'Shanghai',
key: '0-0-1',
},
],
},
],
},
{
label: '北美洲',
value: 'North America',
key: '1',
},
{
label: '南美洲',
value: 'South America',
key: '2',
},
{
label: '南极洲',
value: 'Antarctica',
key: '3',
},
];
</script>
<template>
<h4>单选</h4>
<TreeSelect style="width: 300px" :treeData="treeData">
<template #selectedItem="{ item }">{{ item.label }}</template>
</TreeSelect>
<h4>多选 + 标签内渲染</h4>
<TreeSelect multiple style="width: 300px" :treeData="treeData">
<template #selectedItem="{ item }">{{ item.label }}</template>
</TreeSelect>
<h4>多选 + 替换整个标签</h4>
<TreeSelect :maxTagCount="2" multiple style="width: 300px" :treeData="treeData">
<template #tag="{ item, onClose }">
<Tag closable color="white" @close="onClose">{{ item.value }}</Tag>
</template>
</TreeSelect>
</template>API参考
TreeSelect
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| modelValue | 当前选中的节点的 value(没有 value 时为 key),用 v-model 绑定;多选时只接受数组。传入后即为受控组件,传入 undefined 会清空选中项。 | TypeByMultiple<Multiple, T | undefined, T[]> | undefined |
| defaultValue | 指定默认选中的条目,只在挂载时读取;多选时只接受数组。 | TypeByMultiple<Multiple, T | undefined, T[]> | semiGlobalDefault("TreeSelect", "defaultValue") |
| multiple | 是否多选。多选时所有子项都被选择会自动勾选其父项。 | Multiple | undefined |
| treeData | 节点数据,key 在整棵树内唯一。只有传入新数组才会更新,原地修改数组或节点不会生效。 | TreeNodeData[] | semiDefault("TreeSelect", "treeData", []) |
| keyMaps | 自定义节点中 key、label、value、disabled、children、isLeaf、icon 的字段名。映射了 label 且开启搜索时,需把 treeNodeFilterProp 设为 treeData 的键之一,或自定义 filterTreeNode。 | KeyMapProps | semiGlobalDefault("TreeSelect", "keyMaps") |
| treeNodeLabelProp | 作为选择框中显示文字的节点属性,默认 label。 | string | semiDefault("TreeSelect", "treeNodeLabelProp", "label") |
| treeNodeFilterProp | 搜索时用于匹配输入的节点属性,默认 label。 | string | semiDefault("TreeSelect", "treeNodeFilterProp", "label") |
| filterTreeNode | 是否根据输入项筛选:true 时按 treeNodeFilterProp 对应的属性值匹配,也可以传入自定义的匹配函数。 | Typeboolean | ((inputValue: string, treeNodeString: string, data?: TreeNodeData | undefined) => boolean) | undefined |
| showFilteredOnly | 搜索时只展示过滤后的结果。 | boolean | semiDefault("TreeSelect", "showFilteredOnly", false) |
| searchPosition | 搜索框的位置:dropdown 在下拉面板中,trigger 在选择框内。 | TreeSelectSearchPosition | semiDefault("TreeSelect", "searchPosition", "dropdown") |
| searchPlaceholder | 下拉面板中搜索框的占位文字。 | string | semiGlobalDefault("TreeSelect", "searchPlaceholder") |
| searchAutoFocus | 搜索框自动聚焦。 | boolean | semiDefault("TreeSelect", "searchAutoFocus", false) |
| showSearchClear | 搜索框是否显示清除按钮。 | boolean | semiDefault("TreeSelect", "showSearchClear", true) |
| remote | 是否启用远程搜索:输入时跳过本地过滤,只触发 search 事件,由使用方获取数据并更新 treeData。 | boolean | semiDefault("TreeSelect", "remote", false) |
| expandAll | 展开所有节点,treeData 变化后仍然生效。 | boolean | semiDefault("TreeSelect", "expandAll", false) |
| defaultExpandAll | 初始化时展开所有节点。之后 treeData 的变化不再影响展开状态,需要时使用 expandAll。 | boolean | semiDefault("TreeSelect", "defaultExpandAll", false) |
| defaultExpandedKeys | 默认展开的节点,显示其直接子级。 | string[] | semiGlobalDefault("TreeSelect", "defaultExpandedKeys") |
| expandedKeys | 展开的节点,用 v-model:expandedKeys 绑定。传入后展开状态完全受控。 | string[] | semiGlobalDefault("TreeSelect", "expandedKeys") |
| autoExpandParent | expandedKeys 变化时是否自动展开其中节点的父节点;挂载时总会展开。开启后,展开受控时要先收起所有已展开的子节点才能收起父节点。 | boolean | semiDefault("TreeSelect", "autoExpandParent", false) |
| expandAction | 展开逻辑:false 仅点击展开箭头时展开,click 单击节点展开,doubleClick 双击节点展开。键盘不触发该逻辑。 | ExpandAction | semiDefault("TreeSelect", "expandAction", false) |
| motionExpand | 是否开启节点展开收起的动画;虚拟化时动画关闭。 | boolean | semiDefault("TreeSelect", "motionExpand", true) |
| loadData | 异步加载节点的子级,返回 Promise;未设置 isLeaf 的节点在它存在时显示展开箭头。返回的 Promise 被拒绝后节点可以再次展开重试。 | Type((data: TreeNodeData) => Promise<void>) | undefined |
| loadedKeys | 已加载的节点,配合 loadData 使用,用 v-model:loadedKeys 绑定。 | string[] | semiGlobalDefault("TreeSelect", "loadedKeys") |
| leafOnly | 多选时,值、change 事件的载荷和展示的标签只包含叶子节点。 | boolean | semiDefault("TreeSelect", "leafOnly", false) |
| checkRelation | 多选时节点之间选中状态的关系:related 为父子联动,unRelated 为互不影响。 | CheckRelation | semiDefault("TreeSelect", "checkRelation", "related") |
| disableStrictly | 严格禁用:禁用的节点不能通过父级或子级的选中关系改变状态。 | boolean | semiDefault("TreeSelect", "disableStrictly", false) |
| autoMergeValue | 父节点被选中时,值不再包含它的子孙节点;leafOnly 为 false 时生效。 | boolean | semiDefault("TreeSelect", "autoMergeValue", true) |
| changeWithObject | 布尔属性而不是事件:设为 true 时,modelValue 与 change 的载荷由 value 变为节点对象;受控时 modelValue 与 defaultValue 也要传对象,且必须含 value。 | boolean | semiDefault("TreeSelect", "changeWithObject", false) |
| maxTagCount | 多选时最多显示的标签数量,超出部分以 +N 展示。 | number | semiGlobalDefault("TreeSelect", "maxTagCount") |
| showRestTagsPopover | 超出 maxTagCount 后,hover +N 时是否用 Popover 显示剩余标签。 | boolean | semiDefault("TreeSelect", "showRestTagsPopover", false) |
| restTagsPopoverProps | 剩余标签 Popover 的配置,参考 Popover。 | PopoverProps | semiGlobalDefault("TreeSelect", "restTagsPopoverProps") |
| labelEllipsis | label 超出时是否省略;虚拟化时默认开启。 | boolean | semiGlobalDefault("TreeSelect", "labelEllipsis") |
| showLine | 下拉面板中显示节点之间的连接线。 | boolean | semiDefault("TreeSelect", "showLine", false) |
| virtualize | 列表虚拟化,用于大量节点:height、width、itemSize(必传)。开启后动画关闭。 | Virtualize | semiGlobalDefault("TreeSelect", "virtualize") |
| placeholder | 选择框的占位文字。 | string | semiGlobalDefault("TreeSelect", "placeholder") |
| disabled | 是否禁用。 | boolean | semiDefault("TreeSelect", "disabled", false) |
| size | 选择框尺寸,可选 small、default、large。 | Size | semiDefault("TreeSelect", "size", "default") |
| borderless | 无边框模式。 | boolean | semiDefault("TreeSelect", "borderless", false) |
| validateStatus | 校验状态,只影响样式:default、warning 或 error。 | "default" | "error" | "warning" | "success" | semiGlobalDefault("TreeSelect", "validateStatus") |
| insetLabelId | insetLabel 插槽外层元素的 id,供 aria-labelledby 引用;不传时使用内部生成的 id。 | string | undefined |
| showClear | 有值时选择框是否显示清除按钮。 | boolean | semiDefault("TreeSelect", "showClear", false) |
| clickToHide | 单选时选中节点后是否关闭下拉面板。 | boolean | semiDefault("TreeSelect", "clickToHide", true) |
| clickTriggerToHide | 下拉面板打开时,点击选择框是否关闭面板。 | boolean | semiDefault("TreeSelect", "clickTriggerToHide", true) |
| defaultOpen | 默认展开下拉面板。 | boolean | semiDefault("TreeSelect", "defaultOpen", false) |
| motion | 下拉面板是否有出现和消失的动画。 | boolean | semiDefault("TreeSelect", "motion", true) |
| autoAdjustOverflow | 下拉面板被遮挡时是否自动调整方向。 | boolean | semiDefault("TreeSelect", "autoAdjustOverflow", true) |
| position | 下拉面板的位置,可选值参考 Tooltip 的 position。 | Type"top" | "bottom" | "left" | "right" | "topLeft" | "topRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "bottomLeft" | "bottomRight" | "leftTopOver" | "rightTopOver" | "leftBottomOver" | "rightBottomOver" | semiGlobalDefault("TreeSelect", "position") |
| stopPropagation | 是否阻止下拉面板上的点击事件冒泡;传入字符串时按布尔值处理。 | string | boolean | semiDefault("TreeSelect", "stopPropagation", true) |
| dropdownClassName | 下拉面板的类名。 | string | semiGlobalDefault("TreeSelect", "dropdownClassName") |
| dropdownStyle | 下拉面板的样式。 | StyleValue | semiGlobalDefault("TreeSelect", "dropdownStyle") |
| dropdownMatchSelectWidth | 下拉面板的最小宽度是否等于选择框的宽度。 | boolean | semiDefault("TreeSelect", "dropdownMatchSelectWidth", true) |
| optionListStyle | 节点列表(role="tree" 的元素)的样式。 | StyleValue | semiGlobalDefault("TreeSelect", "optionListStyle") |
| preventScroll | 聚焦时是否阻止浏览器滚动页面以显示新聚焦的元素。 | boolean | semiGlobalDefault("TreeSelect", "preventScroll") |
| triggerTagWrap | 是否允许触发器内的多选标签换行;仅在 multiple、filterTreeNode 开启且 searchPosition 为 trigger 时生效。 | boolean | semiDefault("TreeSelect", "triggerTagWrap", false) |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 选中值变化时触发,v-model 使用;清空时载荷为 undefined。 | Type[value: ByMultiple<Multiple, T | undefined, T[]>] |
| change | 选中值变化时触发,载荷依次为值、节点和触发事件,值与 update:modelValue 相同。清空和多选时分别为 undefined 与数组;通过关闭标签触发时事件为 null;开启 changeWithObject 后值与节点是同一个节点对象。会遮住根元素上同名的原生事件。 | Type[value: ByMultiple<Multiple, T | undefined, T[]>, node: ByMultiple<Multiple, TreeNodeData | undefined, TreeNodeData[]>, event: TreeSelectChangeEvent] |
| update:expandedKeys | 展开的节点变化时触发,v-model:expandedKeys 使用。 | [expandedKeys: string[]] |
| expand | 展开或收起节点时触发,info 含 expanded 与 node。 | Type[expandedKeys: string[], info: { expanded: boolean; node: TreeNodeData; }] |
| update:loadedKeys | 已加载的节点变化时触发,v-model:loadedKeys 使用。 | [loadedKeys: string[]] |
| load | 节点加载完毕时触发,loadedKeys 为已加载节点 key 的 Set。 | Type[loadedKeys: Set<string>, node: TreeNodeData] |
| select | 节点被选中或取消选中时触发,载荷为该节点的 key、是否选中和节点数据。会遮住根元素上同名的原生事件。 | [selectedKey: string, selected: boolean, node: TreeNodeData] |
| search | 搜索框的值变化时触发;filteredExpandedKeys 是因搜索或 modelValue、defaultValue 而展开的节点,可在展开受控时用来展开搜索结果;filteredNodes 是搜索命中的节点。 | Type[input: string, filteredExpandedKeys: string[], filteredNodes: TreeNodeData[]] |
| dropdownVisibleChange | 下拉面板显示或隐藏时触发。组件在 KeepAlive 中停用时会关闭面板并发出 false,不发出 blur。 | [visible: boolean] |
| focus | 焦点从外部进入选择框(含其中的搜索框、清除按钮)或下拉面板时触发,载荷是 FocusEvent;焦点在它们之间移动不重复触发。选中节点并关闭面板后再次点击或按键打开时也会触发,载荷为该次点击或按键的事件;searchAutoFocus 挂载时自动聚焦的载荷为 null。禁用时不触发。会遮住根元素上同名的原生事件。 | [event: MouseEvent | KeyboardEvent | FocusEvent | null] |
| blur | 每次 focus 之后只触发一次:焦点离开选择框和下拉面板时载荷是 FocusEvent,点击外部时是 MouseEvent,选中节点并关闭面板时是该次点击或按键的事件。会遮住根元素上同名的原生事件。 | [event: MouseEvent | KeyboardEvent | FocusEvent] |
| clear | 点击或用键盘触发清除按钮时触发,载荷是触发清除的事件,通过插槽函数清除且没有事件时为 null。 | [event: TreeSelectChangeEvent] |
| keydown | 按键事件,先于 TreeSelect 自身的按键处理触发。会遮住根元素上同名的原生事件。 | [event: KeyboardEvent] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| label | 自定义节点的 label 内容。开启搜索时仍按 treeData 中的 label 文本匹配。 | TreeLabelSlotProps |
| icon | 自定义节点图标,按节点数据返回不同内容。 | TreeIconSlotProps |
| expandIcon | 自定义展开图标。返回单个元素时自动获得 class 与展开的点击处理;也可以用参数自行绑定。 | TreeExpandIconSlotProps |
| fullLabel | 接管整行的内容。带 id、role 与状态的行元素由 TreeSelect 提供,插槽只写行内内容。 | TreeFullLabelSlotProps |
| selectedItem | 自定义已选项:单选时是选择框中显示的内容,多选时是内置标签里的内容;内容为空时单选显示占位文字,多选不渲染该标签。 | TreeSelectSelectedItemSlotProps |
| tag | 多选时替换每个标签,优先于 selectedItem;内容为空时不渲染该标签。 | TreeSelectSelectedItemSlotProps |
| trigger | 替换整个触发器的内容,参数含已选节点、输入值以及 onSearch、onClear、onRemove 方法。 | TypeTreeSelectTriggerSlotProps<T, Multiple> |
| search | 替换搜索框,参数可以直接 v-bind 到 Semi 的 Input 上,其中 inputRef 必须绑定;插槽内容为空时隐藏搜索框。 | TreeSelectSearchSlotProps |
| prefix | 选择框的前缀内容。 | any |
| suffix | 选择框的后缀内容。 | any |
| insetLabel | 选择框内的内嵌标签,同时作为下拉树的名称来源。 | any |
| arrowIcon | 自定义右侧下拉箭头;插槽内容为空时隐藏箭头。showClear 开启且有值时,hover 优先显示清除按钮。 | any |
| clearIcon | 自定义清除按钮的图标,showClear 为 true 时有效;内容为空时使用默认图标。 | any |
| emptyContent | 没有节点或搜索无结果时的内容;插槽内容为空时隐藏空状态。 | any |
| outerTopSlot | 渲染在下拉面板顶部、与节点列表平级的内容;它取代下拉面板中的搜索框。 | any |
| outerBottomSlot | 渲染在下拉面板底部、与节点列表平级的内容。 | any |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
Vue 版的 TreeSelect 没有 className 属性:class、style 和 data-* 等未声明的属性落在根元素上,aria-label、aria-labelledby、aria-describedby、aria-errormessage、aria-invalid、aria-required 落在当前的 combobox 上(见 ARIA)。focus、blur、change、select、keydown 是组件的事件,会遮住根元素上同名的原生事件。
TreeNodeData
不同
TreeNodeData的 key 值要求必填且唯一。label允许重复。value 值非必填。此时v-model、defaultValue、change事件及changeWithObject中所取的 value 属性值将改为 key 值。为了保证行为的符合预期,treeData 中的 value 值或者全部不填写,或者全部填写且唯一,不建议混写。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| value | 属性值 | string|number | - |
| label | 展示的文本,自定义内容使用 #label 插槽 | string|number | - |
| disabled | 是否禁用,多选状态下支持 | boolean | false |
| key | required且要求唯一 | string | - |
| isLeaf | 是否为叶子节点 | boolean | - |
| children | 子节点 | TreeNodeData[] | - |
节点图标使用 #icon 插槽提供,不在数据中声明。
Methods
TreeSelect 通过模板 ref 暴露 search(value) 和 close() 两个方法,类型为 TreeSelectHandle。search 按输入了该值来搜索,先打开下拉面板,需要同时设置 filterTreeNode;close 关闭下拉面板。如果需要在外部自定义搜索框,可以在自定义搜索框值变更时主动调用 search,改变筛选结果。
<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { TreeSelect } from '@fibrous/semi-ui-vue';
import type { TreeSelectHandle } from '@fibrous/semi-ui-vue';
const treeSelect = useTemplateRef<TreeSelectHandle>('treeSelect');
const search = (value: string) => treeSelect.value?.search(value);
</script>
<template>
<TreeSelect ref="treeSelect" filterTreeNode :treeData="treeData" />
</template>
Accessibility
ARIA
- 按 ARIA 1.2 的 combobox 写法,任一时刻只有一个元素是 combobox。它的名称按优先级取:
aria-labelledby、aria-label、实际渲染出的 insetLabel(Vue 为#insetLabel,未传insetLabelId时组件生成 id;有 prefix 时 insetLabel 不渲染,也不作名称来源),都没有时取语言包中的名称:- 不可搜索或
searchPosition="dropdown"时,触发器是 select-only combobox;下拉内的搜索框保持文本框角色,带aria-controls、aria-autocomplete、aria-activedescendant searchPosition="trigger"时,搜索框是 combobox 和唯一的 Tab 停靠点,带aria-autocomplete="list",触发器不再有角色。单选时搜索框在输入前为空,已选文本以aria-describedby关联为它的描述。点击触发器任意位置会把焦点交给搜索框;
- 不可搜索或
- TreeSelect 允许用户设置
aria-describedby、aria-errormessage、aria-invalid、aria-labelledby、aria-required,另外,Form 会为 Form.TreeSelect 自动设置这些属性; - 下拉中
role="tree"的列表与 combobox 使用同一个名称来源:同一组aria-labelledby、同一个aria-label或同一个 insetLabel;都没有时与 combobox 一样取语言包中的名称;
aria-label、aria-labelledby、aria-describedby、aria-errormessage、aria-invalid、aria-required落在当前的 combobox 上:不可搜索时是根元素,单选且搜索框在触发器内时是搜索框的input,多选且搜索框在触发器内时是标签输入框。设置了aria-labelledby时,combobox 不再补默认的aria-label;只有#insetLabel时 combobox 的aria-labelledby指向它;- 下拉中的节点与 Tree 相同:
role="treeitem",带aria-level、aria-setsize、aria-posinset、aria-disabled,可展开的节点带aria-expanded;单选时用aria-selected,多选时用aria-checked(半选为mixed)。#fullLabel的内容由带id、role="treeitem"和这些状态的li包住;
- 节点前的展开箭头和多选复选框只是状态的图示,对读屏软件隐藏,也不接收焦点。
键盘交互
TreeSelect 按 WAI-ARIA Combobox 处理键盘,弹出层是一棵树:焦点始终留在触发器或搜索框上,aria-activedescendant 指向当前节点,当前节点显示焦点环。下拉刚打开时没有当前节点。
- 下拉关闭时:
ArrowDown、ArrowUp、Enter、Space打开下拉;Home、End打开下拉并移到第一个、最后一个可见节点 ArrowDown、ArrowUp:移到下一个、上一个可见节点,第一次按ArrowDown移到第一个节点;Home、End:移到第一个、最后一个可见节点ArrowRight:展开收起的节点;节点已展开时移到它的第一个子节点(RTL 下与ArrowLeft互换)ArrowLeft:收起展开的节点;否则移到父节点Enter、Space:选中当前节点,多选时勾选或取消勾选;禁用节点不响应- 输入字符:下拉打开时,从当前节点往后,移到第一个以输入内容开头的可见节点;快速连续输入的字符合成一个搜索词。下拉关闭时不响应
Esc:关闭下拉
焦点在搜索框里时,只有 ArrowDown、ArrowUp、Enter 用于移动和选择,其余按键(含字符、Space、Home、End、ArrowLeft、ArrowRight)用于编辑文字。
#search 插槽的参数里带有这组 ARIA 属性(aria-activedescendant、aria-controls、aria-autocomplete、名称;在触发器内时为整组 combobox 属性,含 role、aria-expanded),请用 v-bind 把整个参数对象绑定到输入框(Semi Input)上,否则读屏软件不会读出当前节点。参数里的 inputRef 也必须绑定到输入框上,点击触发器内的已选文本时才能把焦点交给它。
showClear 开启、有已选值或搜索文本且未禁用时,触发器内渲染清除按钮。它是原生 button,名称为语言包中的「清空已选值」,在 hover、下拉打开或焦点位于 TreeSelect 内时显示。从触发器或搜索框按 Tab 移到清除按钮,Enter 或 Space 清空,效果与鼠标点击相同,清空后焦点回到触发器或搜索框。多选时也可在搜索框中用 Backspace 删除标签。
示例:
<TreeSelect aria-label="example treeSelect" :treeData="treeData" />
设计变量
| Sass 变量 | 值 | 用法 |
|---|---|---|
| $color-treeSelect_default-bg-default | var(--semi-color-fill-0) | 树选择器选择框背景颜色 - 默认 |
| $color-treeSelect_default-bg-hover | var(--semi-color-fill-1) | 树选择器选择框背景颜色 - 悬停 |
| $color-treeSelect_default-bg-active | var(--semi-color-fill-2) | 树选择器选择框背景颜色 - 按下 |
| $color-treeSelect_default-bg-focus | var(--semi-color-fill-0) | 树选择器选择框背景颜色 - 选中 |
| $color-treeSelect_default-border-default | transparent | 树选择器选择框描边颜色 - 默认 |
| $color-treeSelect_selection-text-default | var(--semi-color-text-0) | 树选择器选择框回填内容文本颜色 - 默认 |
| $color-treeSelect_default-icon-default | var(--semi-color-text-2) | 树选择器选择框图标颜色 - 默认 |
| $color-treeSelect_default-icon-hover | var(--semi-color-primary-hover) | 树选择器选择框清空按钮颜色 - 悬停 |
| $color-treeSelect_default-icon-active | var(--semi-color-primary-active) | 树选择器选择框清空按钮颜色 - 按下 |
| $color-treeSelect_default-border-hover | transparent | 树选择器选择框描边颜色 - 悬浮 |
| $color-treeSelect_default-border-focus | var(--semi-color-focus-border) | 树选择器选择框描边颜色 - 选中 |
| $color-treeSelect_search-border-default | var(--semi-color-fill-0) | 树选择器菜单搜索框描边颜色 - 默认 |
| $color-treeSelect_tag_disabled-bg-default | transparent | 禁用树选择器菜单标签背景颜色 |
| $color-treeSelect_input_disabled-bg-default | var(--semi-color-disabled-fill) | 禁用树选择器选择框背景颜色 |
| $color-treeSelect_input_disabled-text-default | var(--semi-color-disabled-text) | 禁用树选择器选择框文本颜色 |
| $color-treeSelect_input_disabled-bg-hover | var(--semi-color-disabled-fill) | 禁用树选择器选择框背景颜色 - 悬浮 |
| $color-treeSelect_input_placeholder-text-default | var(--semi-color-text-2) | 树选择器选择框占位文本颜色 |
| $color-treeSelect_warning-bg-default | var(--semi-color-warning-light-default) | 警告树选择器选择框背景颜色 - 默认 |
| $color-treeSelect_warning-border-default | var(--semi-color-warning-light-default) | 警告树选择器选择框描边颜色 - 默认 |
| $color-treeSelect_warning-bg-hover | var(--semi-color-warning-light-hover) | 警告树选择器选择框背景颜色 - 悬浮 |
| $color-treeSelect_warning-border-hover | var(--semi-color-warning-light-hover) | 警告树选择器选择框描边颜色 - 悬浮 |
| $color-treeSelect_warning-bg-focus | var(--semi-color-warning-light-default) | 警告树选择器选择框背景颜色 - 选中 |
| $color-treeSelect_warning-border-focus | var(--semi-color-warning) | 警告树选择器选择框描边颜色 - 选中 |
| $color-treeSelect_warning-bg-active | var(--semi-color-warning-light-active) | 警告树选择器选择框背景颜色 - 激活 |
| $color-treeSelect_warning-border-active | var(--semi-color-warning-light-active) | 警告树选择器选择框描边颜色 - 激活 |
| $color-treeSelect_danger-bg-default | var(--semi-color-danger-light-default) | 错误树选择器选择框背景颜色 - 默认 |
| $color-treeSelect_danger-border-default | var(--semi-color-danger-light-default) | 错误树选择器选择框描边颜色 - 默认 |
| $color-treeSelect_danger-bg-hover | var(--semi-color-danger-light-hover) | 错误树选择器选择框背景颜色 - 悬浮 |
| $color-treeSelect_danger-border-hover | var(--semi-color-danger-light-hover) | 错误树选择器选择框描边颜色 - 悬浮 |
| $color-treeSelect_danger-bg-focus | var(--semi-color-danger-light-default) | 错误树选择器选择框背景颜色 - 选中 |
| $color-treeSelect_danger-border-focus | var(--semi-color-danger) | 错误树选择器选择框描边颜色 - 选中 |
| $color-treeSelect_danger-bg-active | var(--semi-color-danger-light-active) | 错误树选择器选择框背景颜色 - 激活 |
| $color-treeSelect_danger-border-active | var(--semi-color-danger-light-active) | 错误树选择器选择框描边颜色 - 激活 |
| $radius-treeSelect | var(--semi-border-radius-small) | 树选择器圆角 |
| $width-treeSelect-border | 1px | 树选择器描边宽度 |
| $width-treeSelect_search_wrapper-border | 1px | 树选择器搜索框描边宽度 |
| $width-treeSelect_hover-border | $border-thickness-control-focus | 树选择器选择框描边宽度 - 悬浮 |
| $width-treeSelect_focus-border | $width-treeSelect_hover-border | 树选择器选择框描边宽度 - 选中 |
| $width-treeSelect_default | 80px | 树选择器最小宽度 |
| $height-treeSelect_default | $height-control-default | 树选择器选择器高度 - 默认 |
| $font-treeSelect_default-lineHeight | $height-treeSelect_default | 树选择器选择器文本行高 |
| $font-treeSelect_default-fontWeight | $font-weight-regular | 树选择器选择器文本字重 |
| $height-treeSelect_small | $height-control-small | 小尺寸树选择器选择器高度 |
| $font-treeSelect_small-lineHeight | $height-treeSelect_small | 小尺寸树选择器选择器文本行高 |
| $height-treeSelect_large | $height-control-large | 大尺寸树选择器选择器文本行高 |
| $font-treeSelect_large-lineHeight | $height-treeSelect_large | 大尺寸树选择器选择器文本行高 |
| $font-treeSelect_prefix_suffix_fontWeight | $font-weight-bold | 树选择器前缀后缀文本字重 |
| $spacing-treeSelect_selection_tagInput_wrapper-paddingX | $spacing-extra-tight | 树选择器多选标签容器水平内边距 |
| $spacing-treeSelect_selection_tagInput_empty-marginLeft | $spacing-extra-tight | 树选择器多选标签容器为空时左侧外边距 |
| $spacing-treeSelect_selection_tagInput_notEmpty-marginLeft | -$spacing-extra-tight | 树选择器多选标签容器不为空时左侧外边距 |
| $spacing-treeSelect_selection-paddingLeft | $spacing-base-tight | 树选择器单选左侧内边距 |
| $spacing-treeSelect_tag-marginX | $spacing-super-tight | 树选择器多选标签水平外边距 |
| $spacing-treeSelect_tag-marginY | 1px | 树选择器多选标签垂直外边距 |
| $spacing-treeSelect_selection_multiple-paddingLeft | 4px | 树选择器多选标签左侧内边距 |
| $spacing-treeSelect_placeholder_multiple-paddingLeft | 8px | 树选择器多选占位文本左侧外边距 |
| $spacing-treeSelect_prefix_text-marginY | 0px | 树选择器前缀文本垂直外边距 |
| $spacing-treeSelect_prefix_text-marginX | $spacing-base-tight | 树选择器前缀文本水平外边距 |
| $spacing-treeSelect_prefix_icon-marginY | 0px | 树选择器前缀图标垂直外边距 |
| $spacing-treeSelect_prefix_icon-marginX | $spacing-tight | 树选择器前缀图标水平外边距 |
| $spacing-treeSelect_selection_withSuffix-paddingRight | 0px | 树选择器有后缀时内容右侧内边距 |
| $color-treeSelect_selection_TriggerSearchItem_disabled-text-default | var(--semi-color-disabled-text) | 带搜索的树选择器触发器占位文本默认颜色 |
| $color-treeSelect_inputTrigger-border-default | none | 带搜索的树选择器触发器描边颜色 |
| $color-treeSelect_inputTrigger-bg-default | transparent | 带搜索的树选择器触发器背景颜色 |
| $color-treeSelect_prefix_suffix_text-default | var(--semi-color-text-2) | 带搜索的树选择器前后缀文本颜色 |
| $width-treeSelect_arrow | 32px | 树选择器展开箭头宽度 |
| $width-treeSelect_option | 230px | 树选择器菜单项宽度 |
| $height-treeSelect_popover | 300px | 树选择器菜单高度 |
| $height-treeSelect_selection_tagInput_wrapper_small | 22px | 树选择器多选搜索,搜索框在选择框时选择框最小高度 - 小尺寸 |
| $height-treeSelect_selection_tagInput_wrapper_default | 30px | 树选择器多选搜索,搜索框在选择框时选择框最小高度 - 默认尺寸 |
| $height-treeSelect_selection_tagInput_wrapper_large | 38px | 树选择器多选搜索,搜索框在选择框时选择框最小高度 - 大尺寸 |