TreeSelect 树选择器

用于多层级树形数据的结构化展示与选取,如文件夹、组织架构、地区分类。

何时使用

  • 需要以树形下拉方式选择层级数据时。

基础用法

最简单的用法,默认为单选模式。

<script setup lang="ts">
import { ref } from "vue";
import { TreeSelect } from "@reglow/reui";

const value = ref("");
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: "NA",
    key: "1",
    children: [
      { label: "美国", value: "USA", key: "1-0" },
      { label: "加拿大", value: "Canada", key: "1-1" },
    ],
  },
];
</script>

<template>
  <TreeSelect v-model="value" :tree-data="treeData" class="w-[260px]" />
</template>

导入

import { TreeSelect } from "@reglow/reui";
import type { TreeNodeData } from "@reglow/reui";

更多示例

多选

设置 multiple 进行多选,所有子项被选中时自动勾选父项。

<script setup lang="ts">
import { ref } from "vue";

const value = ref<string[]>([]);
</script>

<template>
  <TreeSelect v-model="value" :tree-data="treeData" multiple class="w-[260px]" />
</template>

只渲染叶子节点

设置 leafOnly 只展示叶子节点,回调参数也仅返回叶子节点值。

<template>
  <TreeSelect
    v-model="value"
    :tree-data="treeData"
    multiple
    leaf-only
    class="w-[260px]"
  />
</template>

限制标签展示数量

通过 maxTagCount 限制标签数量,超出部分以 +N 展示。

<template>
  <TreeSelect
    v-model="value"
    :tree-data="treeData"
    multiple
    :max-tag-count="2"
    class="w-[260px]"
  />
</template>

hover +N 显示 Popover

设置 showRestTagsPopover 后,hover +N 显示完整标签列表。

<template>
  <TreeSelect
    v-model="value"
    :tree-data="treeData"
    multiple
    :max-tag-count="2"
    show-rest-tags-popover
    class="w-[260px]"
  />
</template>

可搜索

设置 filterTreeNode 开启搜索,默认对 label 值进行搜索。

<template>
  <TreeSelect
    v-model="value"
    :tree-data="treeData"
    filter-tree-node
    class="w-[260px]"
  />
</template>

仅展示匹配结果

设置 showFilteredOnly 只展示匹配节点。

<template>
  <TreeSelect
    :tree-data="treeData"
    filter-tree-node
    show-filtered-only
    class="w-[260px]"
  />
</template>

搜索框位置

通过 searchPosition 设置搜索框位置:dropdown(默认)或 trigger

<template>
  <!-- 搜索框在下拉面板中 -->
  <TreeSelect :tree-data="treeData" filter-tree-node search-position="dropdown" class="w-[260px]" />

  <!-- 搜索框在触发器中 -->
  <TreeSelect :tree-data="treeData" filter-tree-node search-position="trigger" class="w-[260px]" />
</template>

远程搜索

设置 remote 启用远程搜索,输入时触发 search 回调。

<script setup lang="ts">
import { ref } from "vue";

const value = ref("");
const treeData = ref([]);
const loading = ref(false);

const onSearch = (inputValue: string) => {
  if (!inputValue) {
    treeData.value = [];
    return;
  }
  loading.value = true;
  // 模拟远程请求
  setTimeout(() => {
    treeData.value = [
      { label: `${inputValue} - 结果1`, value: `${inputValue}-1`, key: `${inputValue}-1` },
      { label: `${inputValue} - 结果2`, value: `${inputValue}-2`, key: `${inputValue}-2` },
    ];
    loading.value = false;
  }, 1000);
};
</script>

<template>
  <TreeSelect
    v-model="value"
    :tree-data="treeData"
    remote
    filter-tree-node
    search-position="trigger"
    @search="onSearch"
    class="w-[260px]"
  />
</template>

尺寸

通过 size 设置尺寸大小。

<template>
  <TreeSelect :tree-data="treeData" size="small" class="w-[260px]" />
  <TreeSelect :tree-data="treeData" size="default" class="w-[260px]" />
  <TreeSelect :tree-data="treeData" size="large" class="w-[260px]" />
</template>

默认展开

<template>
  <!-- 默认展开所有 -->
  <TreeSelect :tree-data="treeData" default-expand-all class="w-[260px]" />

  <!-- 展开指定节点 -->
  <TreeSelect
    :tree-data="treeData"
    :default-expanded-keys="['0', '0-0']"
    class="w-[260px]"
  />
</template>

展开受控

<script setup lang="ts">
import { ref } from "vue";

const expandedKeys = ref(["0", "0-0"]);
</script>

<template>
  <TreeSelect
    v-model:expanded-keys="expandedKeys"
    :tree-data="treeData"
    class="w-[260px]"
  />
</template>

禁用

<script setup lang="ts">
const treeData = [
  {
    label: "亚洲",
    key: "0",
    children: [
      { label: "中国", key: "0-0", disabled: true },
      { label: "日本", key: "0-1" },
    ],
  },
];
</script>

<template>
  <!-- 整体禁用 -->
  <TreeSelect :tree-data="treeData" disabled class="w-[260px]" />

  <!-- 节点禁用 -->
  <TreeSelect :tree-data="treeData" class="w-[260px]" />
</template>

严格禁用

设置 disableStrictly 开启严格禁用,禁用节点不会被父级选中状态影响。

<template>
  <TreeSelect
    :tree-data="treeData"
    multiple
    disable-strictly
    class="w-[260px]"
  />
</template>

受控

<script setup lang="ts">
import { ref } from "vue";

const value = ref("Shanghai");
</script>

<template>
  <TreeSelect v-model="value" :tree-data="treeData" class="w-[260px]" />
</template>

节点选中关系

设置 checkRelationunRelated,节点间选中互不影响。

<template>
  <TreeSelect
    v-model="value"
    :tree-data="treeData"
    multiple
    check-relation="unRelated"
    class="w-[260px]"
  />
</template>

无边框模式

<template>
  <TreeSelect :tree-data="treeData" borderless class="w-[260px]" />
</template>

目录树模式

<template>
  <TreeSelect :tree-data="treeData" directory class="w-[260px]" />
</template>

异步加载

通过 loadData 动态加载子节点,需在数据中传入 isLeaf

<script setup lang="ts">
const treeData = [
  { label: "加载更多", value: "0", key: "0", isLeaf: false },
  { label: "叶子节点", value: "1", key: "1", isLeaf: true },
];

const loadData = async (node: any) => {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  node.children = [
    { label: "子节点1", value: `${node.key}-0`, key: `${node.key}-0`, isLeaf: true },
    { label: "子节点2", value: `${node.key}-1`, key: `${node.key}-1`, isLeaf: true },
  ];
};
</script>

<template>
  <TreeSelect :tree-data="treeData" :load-data="loadData" class="w-[260px]" />
</template>

选择后不关闭

<template>
  <TreeSelect :tree-data="treeData" :click-to-hide="false" class="w-[260px]" />
</template>

API

Props

属性类型默认值说明
treeDataTreeNodeData[][]树数据
modelValuestring | number | (string | number)[]-当前选中值(v-model)
defaultValuestring | number | (string | number)[]-默认选中值
placeholderstring请选择占位文字
multiplebooleanfalse是否多选
disabledbooleanfalse是否禁用
allowClearbooleantrue是否允许清除
sizesmall | default | largedefault尺寸
borderlessbooleanfalse无边框模式
defaultExpandAllbooleanfalse默认展开所有
expandAllbooleanfalse展开所有(数据更新时生效)
defaultExpandedKeysstring[]-默认展开的 key
expandedKeysstring[]-展开的 key(v-model)
autoExpandParentbooleanfalse自动展开父节点
clickToHidebooleantrue选择后关闭(单选)
defaultOpenbooleanfalse默认展开下拉
filterTreeNodeboolean | ((input, node) => boolean)false开启搜索
searchPositiondropdown | triggerdropdown搜索框位置
searchPlaceholderstring搜索搜索框占位
showFilteredOnlybooleanfalse仅展示匹配节点
treeNodeFilterPropstringlabel搜索匹配属性
remotebooleanfalse远程搜索
checkRelationrelated | unRelatedrelated节点选中关系
leafOnlybooleanfalse仅返回叶子节点
maxTagCountnumber-限制标签数量
showRestTagsPopoverbooleanfalsehover +N 显示 Popover
disableStrictlybooleanfalse严格禁用
directorybooleanfalse目录树模式
loadData(node) => Promise<void>-异步加载
dropdownMaxHeightnumber | string300弹层最大高度
classstring-附加类名

Events

事件说明回调参数
change选中变化(value, node)
search搜索(value, filteredKeys)
expand展开/收起(keys, node)
clear清空()

类型

TreeNodeData:

属性类型默认值说明
labelstring-标签
valuestring | number-
keystring用 value唯一标识
childrenTreeNodeData[]-子节点
disabledbooleanfalse是否禁用
isLeafboolean-是否叶子节点
iconVNode-自定义图标
defaultExpandedbooleanfalse是否默认展开
extrastring-副文本

多选行为

checkRelation说明
related父子关联:选中父节点自动选中子节点,子节点全选时自动勾选父节点(含半选)
unRelated父子不关联:各节点选中状态互不影响

国际化

placeholdersearchPlaceholder、空状态文案默认跟随全局语言(zh-CN / zh-TW / en-US),传 prop 可覆盖。