Skip to content

TreeSelect 树选择器 ​

用于在层级数据中选择单个、多个或勾选一批节点,适合地区、组织架构、分类目录、指标维度等字段。

何时使用 ​

候选项存在父子层级,并希望像 Select 一样在下拉里完成选择时使用 TreeSelect;地区、部门、目录、指标树都是典型场景。平铺枚举用 Select,独立的多列级联用 Cascader;需要直接浏览树结构时使用独立的 Tree 组件。

基础用法 ​

单选点击叶子节点后关闭面板并回显标题;点击分支节点只展开 / 收起。allowClear 提供清空按钮;禁用节点不可点击,也不会在清空时被误删。

杭州已选:hz
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData, TreeSelectValue } from 'x-next';

const value = ref<string | number | undefined>('hz');
const feedback = ref('已选:hz');
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [
      { key: 'hz', title: '杭州' },
      { key: 'nb', title: '宁波' },
      { key: 'wz', title: '温州(暂停服务)', disabled: true },
    ],
  },
];
function changed(value: TreeSelectValue | TreeSelectValue[] | undefined) {
  feedback.value = value ? `已选:${String(value)}` : '已清空';
}
</script>

<template>
  <TreeSelect
    v-model="value"
    :data="data"
    default-expand-all
    allow-clear
    placeholder="请选择城市"
    @change="changed"
  />
  <p>{{ feedback }}</p>
</template>

多选 ​

multiple 开启多选,值始终是数组,面板保持展开直到点击外部或按 Escape。maxTagCount 只折叠展示,不限制数量;tagNowrap 让标签不换行。多选 / 勾选模式下点击节点会清空搜索词(与 Select 一致),需要保留搜索词时用 allowSearch: { retainInputValue: true }。

杭州宁波点击标签 × 试试
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData, TreeSelectValue } from 'x-next';

const value = ref<(string | number)[]>(['hz', 'nb']);
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [
      { key: 'hz', title: '杭州' },
      { key: 'nb', title: '宁波' },
      { key: 'wz', title: '温州(暂停服务)', disabled: true },
    ],
  },
];
function removed(value: TreeSelectValue | undefined) {
  console.log('移除:', value);
}
</script>

<template>
  <TreeSelect
    v-model="value"
    :data="data"
    multiple
    default-expand-all
    allow-clear
    :max-tag-count="2"
    tag-nowrap
    placeholder="可多选城市"
    @remove="removed"
  />
</template>

勾选模式与父子联动 ​

treeCheckable 开启复选框。勾选叶子后父节点自动变为半选;半选节点不出现在值里。默认 checkedStrategy="parent",勾选整个分支时只回填父节点 key。禁用和 disableCheckbox 节点不参与联动,但仍可被父节点联动勾选。

杭州勾选任意节点观察父子联动
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData, TreeSelectValue } from 'x-next';

const value = ref<(string | number)[]>(['hz']);
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [
      { key: 'hz', title: '杭州' },
      { key: 'nb', title: '宁波' },
    ],
  },
];
function changed(value: TreeSelectValue | TreeSelectValue[] | undefined, info: Record<string, unknown>) {
  console.log('当前值:', value, '节点:', info.node);
}
</script>

<template>
  <TreeSelect
    v-model="value"
    :data="data"
    tree-checkable
    default-expand-all
    placeholder="勾选城市"
    @change="changed"
  />
</template>

勾选策略 ​

checkedStrategy 控制回填值的粒度:parent(默认)保留最高层已选节点,child 只保留叶子,all 返回全部勾选节点。切换策略只影响后续回填值,规范业务数据时用 parent 更省心。

浙江省当前值:["zj"]
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect, RadioGroup, Radio } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<(string | number)[]>(['zj']);
const strategy = ref<'parent' | 'child' | 'all'>('parent');
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [
      { key: 'hz', title: '杭州' },
      { key: 'nb', title: '宁波' },
    ],
  },
];
</script>

<template>
  <RadioGroup v-model="strategy">
    <Radio value="parent">parent</Radio>
    <Radio value="child">child</Radio>
    <Radio value="all">all</Radio>
  </RadioGroup>
  <TreeSelect
    v-model="value"
    :data="data"
    tree-checkable
    default-expand-all
    :checked-strategy="strategy"
  />
  <p>当前值:{{ value }}</p>
</template>

严格勾选模式 ​

treeCheckStrictly 取消父子联动,勾选状态完全由业务控制;值为 ['zj'] 时子节点不会被自动勾选。适合「父级只作为分组标题、勾选互相独立」的场景。

浙江省当前值:["zj"]
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<(string | number)[]>(['zj']);
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [
      { key: 'hz', title: '杭州' },
      { key: 'nb', title: '宁波' },
    ],
  },
];
</script>

<template>
  <TreeSelect v-model="value" :data="data" tree-checkable tree-check-strictly default-expand-all />
</template>

搜索与自定义过滤 ​

allowSearch 开启搜索框。默认按标题忽略大小写匹配,命中节点的祖先会保留展示,命中的文字自动高亮。filterTreeNode 可换成按编码等业务字段匹配;search 事件在 searchDelay(默认 500ms)后触发,适合远程查询。

搜索事件:尚未触发
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('');
const input = ref('');
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    code: '330000',
    children: [{ key: 'hz', title: '杭州', code: '330100' }],
  },
];
const filterByCodeOrTitle = (input: string, node: TreeSelectNodeData) =>
  String(node.code ?? '').includes(input) || String(node.title ?? '').includes(input);
</script>

<template>
  <TreeSelect
    v-model="value"
    v-model:input-value="input"
    :data="data"
    allow-search
    :filter-tree-node="filterByCodeOrTitle"
    placeholder="输入城市名或行政区划代码"
    @search="query => console.log('搜索:', query)"
  />
</template>

异步加载子节点 ​

给节点的 isLeaf: false,并传入 loadMore,展开时先请求子级、成功后再展开;加载中的节点显示转圈图标。适合目录、组织架构等大数据量场景,配合 search 事件还能实现远程搜索。

展开节点时加载子级
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('');
const data = ref<TreeSelectNodeData[]>([
  { key: 'region-east', title: '华东大区', isLeaf: false },
]);
const loadRegion = (node: TreeSelectNodeData): Promise<void> =>
  new Promise((resolve) => {
    setTimeout(() => {
      node.children = [
        { key: `${node.key}-a`, title: `${node.title} · 一组` },
        { key: `${node.key}-b`, title: `${node.title} · 二组` },
      ];
      resolve();
    }, 600);
  });
</script>

<template>
  <TreeSelect v-model="value" :data="data" :load-more="loadRegion" placeholder="展开大区加载子级" />
</template>

展开控制 ​

default-expand-all 首次渲染展开全部节点;v-model:expanded-keys 受控展开状态;default-expanded-keys 只指定部分节点;auto-expand-parent(默认开启)会在指定节点参与展开时自动补全祖先。

默认展开 zj
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('');
const expandedKeys = ref<(string | number)[]>(['zj']);
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [{ key: 'hz', title: '杭州' }],
  },
];
</script>

<template>
  <TreeSelect
    v-model="value"
    v-model:expanded-keys="expandedKeys"
    :data="data"
    @expand="keys => console.log('展开:', keys)"
  />
</template>

自定义字段名 ​

fieldNames 把 key、title、children、disabled 等字段映射到业务数据上,无需在进入组件前转换结构。checkable、disableCheckbox、selectable、isLeaf、icon 同样可映射。

设计部当前值:dept-design
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';

const value = ref<string | number | undefined>('dept-design');
const data = [
  {
    id: 'dept',
    name: '产品技术中心',
    sub: [
      { id: 'dept-design', name: '设计部' },
      { id: 'dept-fe', name: '前端组' },
    ],
  },
];
</script>

<template>
  <TreeSelect
    v-model="value"
    :data="data"
    :field-names="{ key: 'id', title: 'name', children: 'sub' }"
    default-expand-all
    placeholder="选择部门"
  />
</template>

值与标题 ​

labelInValue 让值变成 { value, label, raw } 对象,提交表单或保存草稿时无需再反查标题;数据中已不存在的选中值会保留并在标签里回显,fallbackOption 关闭后则直接丢弃。

杭州change 载荷:{"value":"hz","label":"杭州"}
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData, TreeSelectValue } from 'x-next';

const value = ref<{ value: string | number; label: string } | undefined>({ value: 'hz', label: '杭州' });
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [{ key: 'hz', title: '杭州' }],
  },
];
function changed(value: TreeSelectValue | TreeSelectValue[] | undefined) {
  console.log('当前值:', value);
}
</script>

<template>
  <TreeSelect v-model="value" :data="data" label-in-value default-expand-all allow-clear @change="changed" />
</template>

自定义节点 ​

title 插槽拿到节点状态(checked / halfChecked / selected / expanded / level),node-icon 与 switcher-icon 分别替换节点前缀图标和展开箭头;数据里的 icon 字段也可以直接给节点配置图标函数。

杭州集群当前值:hz
vue
<template>
  <TreeSelect v-model="value" :data="data" default-expand-all>
    <template #title="{ node, checked }">
      <span>
        {{ node.title }}
        <i v-if="node.status">{{ node.status === 'healthy' ? '●' : '▲' }}</i>
      </span>
    </template>
  </TreeSelect>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('hz');
const data: TreeSelectNodeData[] = [
  {
    key: 'cloud',
    title: '云平台',
    children: [
      { key: 'hz', title: '杭州集群', status: 'healthy' },
      { key: 'nb', title: '宁波集群', status: 'warning' },
    ],
  },
];
</script>

连接线与整行节点 ​

showLine 显示层级连接线,最后一个子节点的线止于自身行中;blockNode 让节点占据整行、悬停与选中背景铺满,适合表格筛选器里的窄宽度选择框。两者可以组合。

太仓当前值:sz-tc;节点模式:blockNode
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect, Switch } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('sz-tc');
const block = ref(true);
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [
      { key: 'hz', title: '杭州' },
      { key: 'nb', title: '宁波' },
    ],
  },
];
</script>

<template>
  <Switch v-model="block" checked-text="整行" unchecked-text="缩进" />
  <TreeSelect
    v-model="value"
    :data="data"
    show-line
    :block-node="block"
    default-expand-all
    allow-clear
    placeholder="带连接线的树"
  />
</template>

禁用、错误、加载与尺寸 ​

disabled 关闭交互,error 标记校验失败,loading 展示加载图标并在面板内显示加载态,size 支持 mini / small / medium / large。这些状态与 Select 保持一致,可直接放进 FormItem。

可选节点 A
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect, Button } from 'x-next';

const value = ref<string | number | undefined>('a');
const loading = ref(false);
const data = [
  { key: 'a', title: '可选节点 A' },
  { key: 'b', title: '可选节点 B' },
];
</script>

<template>
  <TreeSelect :data="data" size="mini" placeholder="mini" />
  <TreeSelect :data="data" size="small" placeholder="small" />
  <TreeSelect :data="data" size="medium" placeholder="medium" />
  <TreeSelect :data="data" size="large" placeholder="large" />
  <TreeSelect :data="data" disabled placeholder="禁用" />
  <TreeSelect v-model="value" :data="data" error placeholder="错误" />
  <TreeSelect :data="data" :loading="loading" placeholder="加载" />
  <Button size="small" @click="loading = !loading">{{ loading ? '结束加载' : '模拟加载' }}</Button>
</template>

缺失值回显 ​

当值对应的节点不在当前 data(数据权限、分页、远程未命中)时,默认保留该值并以原始 key 回显;fallbackOption 传函数可自定义回显内容,传 false 则丢弃不存在节点。下拉里也会把这类值显示为额外节点,方便用户主动清除。

归档节点(archived-node)选中的节点暂不在 data 中
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';

const value = ref<string | number | undefined>('archived-node');
const data = [
  { key: 'a', title: '可选节点 A' },
  { key: 'b', title: '可选节点 B' },
];
const fallback = (value: string | number) => ({
  key: value,
  title: `归档节点(${String(value)})`,
});
</script>

<template>
  <TreeSelect v-model="value" :data="data" :fallback-option="fallback" allow-clear />
</template>

虚拟列表 ​

数据量大时传入 virtualListProps 开启虚拟滚动,height 控制可视区高度;关闭 scrollbar 可退回原生滚动条。搜索命中的节点同样按扁平结果虚拟化,不会因为层级展开而失效。

当前值:
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('');
const data: TreeSelectNodeData[] = Array.from({ length: 240 }, (_, index) => ({
  key: `node-${index + 1}`,
  title: `数据节点 ${index + 1}`,
  isLeaf: true,
}));
</script>

<template>
  <TreeSelect
    v-model="value"
    :data="data"
    :virtual-list-props="{ height: 220 }"
    allow-search
    allow-clear
    placeholder="240 个扁平节点"
  />
</template>

下拉定制与批量操作 ​

header / footer 插槽承载批量操作,show-header-on-empty / show-footer-on-empty 决定空态时是否保留;empty 替换空态。配合实例方法 checkAll() 与 expandAll() 可以做出「全选 / 展开全部」的工具条。

使用页头批量操作
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect, Button } from 'x-next';
import type { TreeSelectInstance, TreeSelectNodeData } from 'x-next';

const value = ref<(string | number)[]>([]);
const select = ref<TreeSelectInstance>();
const data: TreeSelectNodeData[] = [
  {
    key: 'east',
    title: '华东区',
    children: [
      { key: 'east-hz', title: '杭州' },
      { key: 'east-nb', title: '宁波' },
    ],
  },
];
</script>

<template>
  <TreeSelect ref="select" v-model="value" :data="data" tree-checkable default-expand-all>
    <template #header>
      <Button size="mini" @click="select?.checkAll(true)">全选</Button>
      <Button size="mini" @click="select?.checkAll(false)">清空</Button>
      <Button size="mini" @click="select?.expandAll(true)">展开全部</Button>
    </template>
    <template #footer>已选 {{ value.length }} 项</template>
  </TreeSelect>
</template>

自定义触发器与实例方法 ​

默认触发器承载输入与标签;如需完全自定义,使用 trigger 插槽并绑定 onKeydown,同时补齐 role="combobox" 与 ARIA。实例方法提供 focus() / blur() / expandAll() / checkAll()。

当前值:未选择;面板:关闭
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('');
const popup = ref(false);
const data: TreeSelectNodeData[] = [
  {
    key: 'east',
    title: '华东区',
    children: [{ key: 'east-hz', title: '杭州' }],
  },
];
</script>

<template>
  <TreeSelect v-model="value" v-model:popup-visible="popup" :data="data" default-expand-all>
    <template #trigger="{ popupVisible, disabled, treeId, activeDescendant, onKeydown }">
      <button
        type="button" role="combobox" :disabled="disabled" aria-label="自定义地区选择"
        aria-haspopup="tree" :aria-expanded="popupVisible" :aria-controls="treeId"
        :aria-activedescendant="activeDescendant" @keydown="onKeydown"
      >{{ value || '选择地区' }}</button>
    </template>
  </TreeSelect>
</template>

在 Form 中校验 ​

放在 FormItem 中即可继承尺寸、禁用与校验状态;值变化会触发 validateTrigger。必填校验使用 FormItem 的规则,不要依赖原生表单控件。

点击校验查看结果
vue
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { Form, FormItem, TreeSelect, Button, Space } from 'x-next';
import type { FieldRule, FormInstance, TreeSelectNodeData } from 'x-next';

const state = reactive<{ region: string | number | undefined }>({ region: undefined });
const rules: Record<string, FieldRule[]> = { region: [{ required: true, message: '请选择归属地区' }] };
const form = ref<FormInstance>();
const result = ref('');
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [{ key: 'hz', title: '杭州' }],
  },
];
const validate = async () => {
  const errors = await form.value!.validate();
  result.value = errors ? '校验失败' : '校验通过';
};
</script>

<template>
  <Form ref="form" :model="state" :rules="rules">
    <FormItem field="region" label="归属地区" required>
      <TreeSelect v-model="state.region" :data="data" default-expand-all allow-clear />
    </FormItem>
    <Button type="primary" @click="validate">校验</Button>
    <p>{{ result }}</p>
  </Form>
</template>

键盘与无障碍 ​

面板打开后:↑ / ↓ 在可见节点间移动,→ 展开当前节点或进入第一个子节点,← 收起或回到父节点,Enter 选中节点,勾选模式下 空格 切换勾选,Escape 关闭面板,Tab 离开并关闭。Home / End 在搜索框为空时跳到首 / 末节点。触发器是 role="combobox" 并关联 aria-controls / aria-activedescendant,树容器是 role="tree",节点带 aria-level、aria-selected、aria-checked(半选为 mixed)。

当前值:;焦点:不在
vue
<script setup lang="ts">
import { ref } from 'vue';
import { TreeSelect } from 'x-next';
import type { TreeSelectNodeData } from 'x-next';

const value = ref<string | number | undefined>('');
const popup = ref(false);
const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    children: [{ key: 'hz', title: '杭州' }],
  },
];
</script>

<template>
  <TreeSelect
    v-model="value"
    v-model:popup-visible="popup"
    :data="data"
    default-expand-all
    aria-label="键盘选择地区"
    placeholder="方向键选择,Enter 确认"
  />
</template>

按需导入 ​

ts
import { TreeSelect } from 'x-next';

推荐公开样式入口,自动包含 base、SelectView、Checkbox、Scrollbar、Spin、Trigger 等内部依赖:

ts
import 'x-next/style/tree-select';

直接使用 .css 时须自行补齐上述依赖;可读取包内 dist/style/dependencies.json 核对。

TreeSelect Props ​

参数说明类型默认值
modelValue绑定值,勾选 / 多选为数组TreeSelectKey | TreeSelectLabelValue | Arrayundefined
defaultValue默认值(非受控)同上单选 undefined,多选 / 勾选 []
multiple是否多选booleanfalse
treeCheckable是否开启勾选模式,值始终为数组booleanfalse
treeCheckStrictly勾选模式是否取消父子联动booleanfalse
checkedStrategy勾选回填策略'all' | 'parent' | 'child''parent'
data树数据TreeSelectNodeData[][]
fieldNames自定义节点字段名object-
labelInValue值是否包含标题booleanfalse
selectable节点可选规则,支持 'leaf' 或方法boolean | 'leaf' | functiontrue
allowSearch是否允许搜索boolean | { retainInputValue?: boolean }多选 / 勾选 true,单选 false
allowClear是否允许清空booleanfalse
filterTreeNode过滤节点方法,false 关闭过滤boolean | functiontrue
searchDelaysearch 事件触发延迟number500
inputValue搜索输入值(v-model)string-
defaultInputValue默认搜索输入值string''
size尺寸'mini' | 'small' | 'medium' | 'large'跟随全局配置
placeholder占位提示string-
loading是否加载中booleanfalse
disabled是否禁用booleanfalse
error是否错误状态booleanfalse
bordered是否显示边框booleantrue
maxTagCount最多展示标签数,0 不限制number0
tagNowrap标签是否不换行booleanfalse
popupVisible面板显示状态(v-model)booleanundefined
defaultPopupVisible面板默认显示状态booleanfalse
unmountOnClose关闭时销毁面板booleanfalse
popupContainer弹出层挂载容器string | HTMLElement-
triggerProps触发器配置object-
defaultExpandAll默认展开全部节点booleanfalse
expandedKeys展开节点(v-model)Array<string | number>undefined
defaultExpandedKeys默认展开节点Array<string | number>[]
autoExpandParent是否自动展开父节点booleantrue
showLine是否显示连接线booleanfalse
blockNode节点占据整行booleanfalse
virtualListProps虚拟列表配置,传入即开启object-
scrollbar是否开启滚动条或滚动条配置boolean | objecttrue
maxHeight下拉列表最大高度number | string300
loadMore异步加载子节点(node) => Promise<void>-
fallbackOption自定义缺失值显示,false 丢弃boolean | (key) => nodetrue
formatLabel格式化显示内容(data) => string-
showHeaderOnEmpty空态是否显示页头booleanfalse
showFooterOnEmpty空态是否显示页脚booleanfalse

TreeSelect Events ​

事件名说明回调参数
update:modelValue值更新时触发value
update:inputValue搜索输入更新时触发inputValue
update:popupVisible面板显隐更新时触发visible
update:expandedKeys展开节点更新时触发keys
change值变化时触发value, info,info 含 node / checked / selected
input-value-change搜索输入变化时触发inputValue
search用户搜索时触发(searchDelay 后)inputValue
popup-visible-change面板显隐变化时触发visible
clear点击清空按钮时触发event
remove关闭多选标签时触发removed
expand展开状态变化时触发keys, info,info 含 node / expanded
dropdown-scroll下拉滚动时触发event
node-click点击(勾选)节点时触发value, info
focus默认触发器聚焦FocusEvent
blur默认触发器失焦FocusEvent

TreeSelect Slots ​

插槽名说明
title自定义节点标题;参数 { node, value, title, level, checked, halfChecked, selected, expanded, disabled, isLeaf }
node-icon节点前缀图标;参数 { node }
switcher-icon展开 / 收起图标;参数 { node, expanded, loading }
label选择框显示内容;参数 { data },data 为 { value, label, raw }
header下拉页头
footer下拉页脚
empty空状态内容
prefix选择框前缀元素
arrow-icon箭头图标
loading-icon加载中图标
search-icon搜索图标
trigger自定义触发元素;参数 { popupVisible, disabled, treeId, activeDescendant, onKeydown }

TreeSelect Methods ​

使用组件 ref,类型可导入 TreeSelectInstance。

方法说明类型
focus聚焦默认触发器() => void
blur失焦默认触发器() => void
expandAll展开 / 收起全部可展开节点,默认展开(expanded?: boolean) => void
checkAll全选 / 清空勾选,仅勾选模式生效(checked?: boolean) => void

节点数据 ​

ts
import type { TreeSelectNodeData } from 'x-next';

const data: TreeSelectNodeData[] = [
  {
    key: 'zj',
    title: '浙江省',
    disabled: false,
    checkable: true,
    disableCheckbox: false,
    selectable: true,
    isLeaf: false,
    children: [{ key: 'hz', title: '杭州' }],
  },
];
字段说明类型默认值
key节点键值,全局唯一;不传按路径生成string | number-
title节点标题string取 key
children子节点TreeSelectNodeData[]-
disabled是否禁用(不可选、不可勾选、不参与联动)booleanfalse
checkable是否可勾选booleantrue
disableCheckbox是否禁用复选框(仍可被父节点联动)booleanfalse
selectable是否可选中booleantrue
isLeaf是否叶子节点(配合 loadMore)boolean无子节点即叶子
icon节点前缀图标() => VNode-

无障碍 ​

  • 触发器输入为 role="combobox",带 aria-haspopup="tree"、aria-expanded、aria-controls 和 aria-activedescendant。
  • 树容器为 role="tree",节点为 role="treeitem",带 aria-level、aria-posinset、aria-setsize、aria-selected、aria-expanded、aria-checked(半选为 mixed)。
  • 键盘完整支持 ↑ / ↓ / ← / → / Home / End / Enter / 空格 / Escape / Tab。
  • 标签关闭按钮与清空按钮均为真实按钮并提供无障碍名称;移除标签后焦点回到输入框。

已知限制 ​

  • 勾选模式下 treeCheckStrictly 为真时半选概念不生效,值完全由业务控制,请保持值与 data 同步。
  • checkedStrategy 在 treeCheckStrictly 下不生效(严格模式直接返回勾选集合)。
  • loadMore 依赖节点的 isLeaf: false 标记;数据里已有 children 的节点不会再触发加载。
  • 搜索为前端过滤;远程搜索请设置 filterTreeNode=false,用 @search 请求数据并替换 data。
  • 节点 key 必须唯一;重复键会退化为路径键并在控制台告警。
  • 与 Arco 的差异:checkedStrategy 默认 parent(Arco 默认 all),并在其基础上提供 child;值可为 labelInValue 对象且附带 raw 原始节点,属于 x-next 的扩展。