FxCascader 级联选择
如果选项具有清晰的层级结构,可以使用 Cascader 来查看和选择它们。基于 FxInput + FxTooltip + 内置 FxCascaderPanel 实现,不依赖任何 UI 框架,样式走 @fx/styles token。
FxCascader 属于 @fx/components。
基础用法
options 为多级数组,每项含 value / label / children。通过 props.expand-trigger 控制下级展开方式(click / hover)。
禁用选项
在选项数据中标记 disabled: true 即可禁用该项。字段名可通过 props.disabled 自定义。
可清空
clearable 开启清空按钮,选中后 hover 显示,点击清空所有选中。
自定义清空图标
通过 clear-icon 自定义清空图标(字符串走 FxIcon,亦可传组件)。
显示层级与分隔符
show-all-levels 控制是否显示完整路径(默认 true,设为 false 仅显示末级)。separator 自定义分隔符。
多选
通过 :props="{ multiple: true }" 开启多选,v-model 接收二维路径数组。注意 props 必须传对象变量,不能内联字面量(内联会导致响应式失效)。
折叠 tag
多选时 collapse-tags 折叠超出 max-collapse-tags 的 tag 为 +N,collapse-tags-tooltip 开启 hover 查看全部。
任意一级可选
props.check-strictly 让父子节点不联动,任意一级(含非叶子)都可直接选择。
动态加载
props.lazy = true + props.lazy-load 动态加载子节点。lazy-load(node, resolve) 中 node 是当前点击节点,resolve(data) 加载完成回调必须调用。通过 leaf 字段(可 props.leaf 自定义)标记叶子节点。
可搜索
filterable 开启搜索,输入关键字从扁平化节点中筛选匹配项。filter-method 自定义匹配逻辑,debounce 控制防抖(ms)。
自定义字段
通过 props 配置项自定义 value / label / children / disabled / leaf 字段名,适配任意后端数据结构。
自定义节点内容
通过 default 插槽自定义节点内容,作用域参数 { node, data }(node 为 Node 对象,data 为原始数据)。
自定义建议项
通过 suggestion-item 插槽自定义搜索建议项内容,作用域参数 { item }(CascaderNode)。
级联面板
FxCascaderPanel 是 FxCascader 的核心面板组件,可独立使用,支持单选 / 多选 / 动态加载等全部能力。
自定义 tag
通过 tag 插槽自定义多选 tag。使用该插槽后 collapse-tags / collapse-tags-tooltip / max-collapse-tags 将失效。作用域参数 { data, deleteTag }。
选中展示策略
多选模式下,show-checked-strategy 控制选中值如何展示:
child(默认):展示所有选中的叶子节点parent:当某父节点的子节点全选时,仅展示该父节点
点击节点即勾选
仅 multiple 或 check-strictly 模式生效。check-on-click-node 让点击节点行即切换勾选(无需点 prefix 图标),show-prefix 控制是否显示 radio/checkbox 前缀。
自定义头尾
通过 header / footer 插槽自定义下拉的顶部 / 底部内容。header 常用于放置全选 / 快速操作,footer 常用于放置清空 / 确认按钮。
虚拟滚动
filterable + virtual-scroll 同时为搜索建议列表和面板菜单列启用虚拟滚动(FxFixedSizeList),适合千级以上节点场景(如全量地区数据)。item-size 指定行高(需与实际项高一致,默认 34),height 控制菜单/建议列表高度(默认 204)。面板 DOM 默认保留(persistent=true),二次打开瞬间响应。
自定义建议宽度
搜索时建议面板默认按匹配项最大宽度撑开。若通过 suggestion-item 插槽自定义内容导致宽度计算不准,可用 fit-input-width 让建议宽度跟随 input:值为 true 等宽于 input,值为 number 则固定像素宽。
fit-input-width仅影响搜索时的建议面板,不影响默认级联面板。
API
FxCascader Attributes
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| model-value / v-model | 绑定值 | string | number | (string|number)[] | — |
| options | 可选项数据 | CascaderOption[] | — |
| props | 配置项,见下方 CascaderProps | CascaderProps | — |
| size | 输入框尺寸 | 'large' | 'default' | 'small' | default |
| placeholder | 占位文字 | string | — |
| disabled | 是否禁用 | boolean | false |
| clearable | 是否可清空 | boolean | false |
| clear-icon | 自定义清空图标。字符串为 IconString 类型(即 FxIcon 图标名,如 ep:edit、ant-design:home、svg:xxx),亦可传组件 | string | Component | ep:circle-close |
| show-all-levels | 是否显示完整路径 | boolean | true |
| separator | 分隔符 | string | ' / ' |
| collapse-tags | 多选是否折叠 tag | boolean | false |
| collapse-tags-tooltip | 折叠 tag 是否 hover 显示全部 | boolean | false |
| max-collapse-tags | 折叠时最大展示 tag 数 | number | 1 |
| max-collapse-tags-tooltip-height | 折叠 tag 浮层最大高度 | string | number | — |
| tag-type | tag 类型 | 'primary' | 'success' | 'info' | 'warning' | 'danger' | info |
| tag-effect | tag 主题 | 'dark' | 'light' | 'plain' | light |
| filterable | 是否可搜索 | boolean | false |
| filter-method | 自定义搜索逻辑 | (node, keyword) => boolean | 按文本包含 |
| debounce | 搜索防抖(ms) | number | 300 |
| before-filter | 过滤前置钩子,返回 false 或 reject 的 Promise 则中止 | (value) => boolean | Promise<unknown> | — |
| virtual-scroll | 建议列表虚拟滚动 | boolean | false |
| item-size | 虚拟滚动行高(px) | number | 34 |
| height | 菜单/建议列表高度(px) | number | 204 |
| fit-input-width | 建议宽度跟随 input(number 为固定像素) | boolean | number | false |
| show-checked-strategy | 多选选中展示策略 | 'parent' | 'child' | child |
| placement | 下拉位置 | Placement | bottom-start |
| fallback-placements | 浮层备选位置 | Placement[] | — |
| popper-class | 浮层附加类名 | string | — |
| popper-style | 浮层附加样式 | CSSProperties | — |
| popper-options | 浮层定位选项(floating-ui) | Record<string, unknown> | — |
| teleported | 浮层是否 teleport 到 body | boolean | true |
| effect | 浮层主题 | 'dark' | 'light' | light |
| persistent | 下拉关闭后是否保留 DOM(默认 true,保留可避免回显丢失和重复初始化开销) | boolean | true |
| empty-values | 空值列表(视为未选择) | unknown[] | — |
| value-on-clear | 清空时回填的值 | unknown | — |
| check-on-click-node | 点击节点即勾选(透传到 props) | boolean | false |
| show-prefix | 是否显示 radio/checkbox 前缀(透传到 props) | boolean | — |
| validate-event | 是否触发表单校验 | boolean | true |
FxCascader Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| change | 绑定值变化时触发 | (value: CascaderValue) => void |
| expand-change | 展开选项变化时触发 | (value: CascaderValue) => void |
| blur | 失焦时触发 | (event: FocusEvent) => void |
| focus | 聚焦时触发 | (event: FocusEvent) => void |
| clear | 点击清空图标时触发 | () => void |
| visible-change | 下拉显隐变化时触发 | (value: boolean) => void |
| remove-tag | 多选移除 tag 时触发 | (value) => void |
FxCascader Slots
| 名称 | 说明 | 作用域参数 |
|---|---|---|
| default | 自定义节点内容 | { node, data } |
| empty | 无匹配数据时的内容 | — |
| prefix | 输入框前缀 | — |
| suggestion-item | 自定义搜索建议项 | { item: CascaderNode } |
| tag | 自定义多选 tag(使用后 collapse 相关失效) | { data: Tag[], deleteTag: (tag) => void } |
| header | 下拉顶部内容 | — |
| footer | 下拉底部内容 | — |
FxCascader Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| getCheckedNodes | 获取当前选中节点(leafOnly=true 仅叶子) | (leafOnly?: boolean) => CascaderNode[] | undefined |
| cascaderPanelRef | 面板实例 | Ref<FxCascaderPanelInstance> |
| togglePopperVisible | 切换浮层显隐 | (visible?: boolean) => void |
| contentRef | 浮层内容 DOM | ComputedRef<HTMLElement | null> |
| presentText | 选中内容文本 | ComputedRef<string> |
| focus | 聚焦输入框 | () => void |
| blur | 失焦输入框 | () => void |
CascaderPanel API
FxCascaderPanel Attributes
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| model-value / v-model | 绑定值 | CascaderValue | — |
| options | 可选项数据 | CascaderOption[] | — |
| props | 配置项,见下方 CascaderProps | CascaderProps | — |
| height | 菜单单列滚动区高度(px) | number | 204 |
| border | 是否显示外边框 | boolean | true |
| render-label | 自定义节点 label 渲染函数 | (node, data) => VNodeChild | — |
FxCascaderPanel Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| change | 绑定值变化时触发 | (value: CascaderValue) => void |
| update:modelValue | 绑定值变化时触发 | (value: CascaderValue) => void |
| expand-change | 展开选项变化时触发 | (value) => void |
| close | 关闭面板事件(Cascader 内嵌时用于收起判断) | () => void |
FxCascaderPanel Slots
| 名称 | 说明 | 作用域参数 |
|---|---|---|
| default | 自定义节点内容 | { node, data } |
| empty | 无数据时的内容 | — |
FxCascaderPanel Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| getCheckedNodes | 获取当前选中节点(leafOnly=true 仅叶子) | (leafOnly?: boolean) => CascaderNode[] | undefined |
| clearCheckedNodes | 清空选中节点 | () => void |
| calculateCheckedValue | 重算选中值 | () => void |
| handleCheckChange | 切换节点勾选 | (node, checked, checkStrictly?) => void |
| getFlattedNodes | 获取扁平化节点 | (leafOnly?) => CascaderNode[] |
| scrollToExpandingNode | 滚动到展开节点 | () => void |
CascaderProps
通过 props 属性传入对象,用于字段别名 / 触发方式 / 多选 / 严格 / 懒加载等。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| expandTrigger | 下级展开触发方式 | 'click' | 'hover' | click |
| multiple | 是否多选 | boolean | false |
| checkStrictly | 父子不联动(任一级可选) | boolean | false |
| emitPath | 选中时是否返回完整路径数组,false 仅返回节点值 | boolean | true |
| lazy | 是否懒加载子节点 | boolean | false |
| lazyLoad | 懒加载方法(lazy 为 true 时生效) | (node, resolve, reject) => void | — |
| value | 节点 value 字段名 | string | value |
| label | 节点 label 字段名 | string | label |
| children | 节点 children 字段名 | string | children |
| disabled | 节点 disabled 字段名或判断函数 | string | ((data, node) => boolean) | disabled |
| leaf | 节点 leaf 字段名或判断函数 | string | ((data, node) => boolean) | leaf |
| hoverThreshold | hover 展开延迟阈值(ms) | number | 500 |
| checkOnClickNode | 点击节点即切换勾选(多选 / 严格模式) | boolean | false |
| checkOnClickLeaf | 点击叶子节点即勾选 | boolean | true |
| showPrefix | 是否显示 radio / checkbox 前缀 | boolean | true |
类型声明
展开查看
ts
type CascaderNodeValue = string | number
type CascaderNodePathValue = CascaderNodeValue[]
type CascaderValue =
| CascaderNodeValue
| CascaderNodePathValue
| (CascaderNodeValue | CascaderNodePathValue)[]
type ExpandTrigger = "click" | "hover"
type Resolve = (data: any) => void
type LazyLoad = (node: CascaderNode, resolve: Resolve, reject: () => void) => void
interface CascaderOption extends Record<string, unknown> {
label?: string
value?: CascaderNodeValue
children?: CascaderOption[]
disabled?: boolean
leaf?: boolean
}
interface CascaderProps {
expandTrigger?: ExpandTrigger
multiple?: boolean
checkStrictly?: boolean
emitPath?: boolean
lazy?: boolean
lazyLoad?: LazyLoad
value?: string
label?: string
children?: string
disabled?: string | ((data: CascaderOption, node: CascaderNode) => boolean)
leaf?: string | ((data: CascaderOption, node: CascaderNode) => boolean)
hoverThreshold?: number
checkOnClickNode?: boolean
checkOnClickLeaf?: boolean
showPrefix?: boolean
}
class CascaderNode {
readonly uid: number
readonly level: number
readonly value: CascaderNodeValue
readonly label: string
readonly pathNodes: CascaderNode[]
readonly pathValues: CascaderNodePathValue
readonly pathLabels: string[]
childrenData: CascaderOption[] | null
children: CascaderNode[]
text: string
loaded: boolean
checked: boolean
indeterminate: boolean
loading: boolean
readonly isDisabled: boolean
readonly isLeaf: boolean
readonly valueByOption: CascaderNodeValue | CascaderNodePathValue
calcText(allLevels: boolean, separator: string): string
doCheck(checked: boolean): void
}