跳转到内容

级联选择 cascader

数据录入组件。三层同源:无头内核给出解剖与状态机,Vue 组件与自定义元素只是它的两层外壳,行为完全一致。

示例

基础用法

collection 是层级、显示文本与禁用的唯一事实源;levels 按深度摊开,每层一个 column

收货地区

当前路径:(未选)

中间层可选

change-on-select 让分支自己也能落值;选中分支后浮层不收起,还能接着往下挑

栏目

当前路径:(未选)

悬停展开

expand-trigger 改成 hover 后,指针划过分支即开子列,只挪展开路径不抢焦点;键盘仍走右方向键

方向

当前路径:(未选)

多选

选中的是一组路径,落值后浮层不收起、焦点留在列里接着挑;再点一次即取消

采购清单

已选 1 条:fruit/apple

形态

variant 只改触发框的底色与描边用法,浮层与列不跟着变

outline
subtle
ghost

语气

tone 决定用哪族颜色,与 variant 正交;这里固定 subtle 形态,只看语气这一轴

brand
neutral
success
warning
danger
info

尺寸

不传 size 即默认档;触发框与列里的条目一起换档

sm
默认
lg

校验状态

invalid 让 trigger 报 aria-invalid、描边换成错误色;浮层照常展开,判定归宿主,这里是没选就报错

所属部门

这一项必填

后端字段映射

collection 只认 value / label / disabled / children 这几个名字,后端字段不一致就在进组件前转一道

服务区域

选中的是转换后的 value:(未选)

条目自定义内容

条目里放什么由作者定:文本两侧各加一段,是不是分支直接读 item 的 branch

团队

当前团队:(未选)

子节点按需加载

先给分支塞一个禁用的占位子节点让子列开得出来,展开到它时才去取真数据换掉占位

收货地区

当前路径:(未选)

长列表只渲可视区

列自己就是滚动容器:按滚动位置切一段挂出来,其余交给撑高块,焦点那一条无论在不在窗口里都挂着

货位(每仓 1000 条)

当前货位:(未选)

级联勾选与回显策略

multiple 加 cascade 内建父子传导:点分支整枝勾上、子全勾父勾、部分勾中半选;对外值按 checked-strategy 收敛(默认只收叶),半选标记从插槽作用域的 isIndeterminate 取

投放品类

选中值(默认只收叶):iOS

浮层底栏

content 的子节点全由作者写:列装进一层横排容器,底栏与它并列,就横跨了全部列

采购清单

已选:fruit/apple

命令式聚焦与展开

trigger 部件渲染的就是原生按钮,模板 ref 拿到它即可 focus / blur;开合走根插槽的 setOpen

收货地区

产物

自定义元素<xh-cascader>
Vue 组件XhCascaderClearTrigger XhCascaderColumn XhCascaderContent XhCascaderIndicator XhCascaderItem XhCascaderItemIndicator XhCascaderItemText XhCascaderLabel XhCascaderPositioner XhCascaderRoot XhCascaderTrigger XhCascaderValueText
组合式函数useCascader
状态机cascaderMachine
皮肤@xihan-ui/styles/cascader.css

解剖

部件名即 data-part 属性值,也是皮肤的选择器。加粗的是必备部件,不渲染它组件不工作(Web Components 适配器会在诊断通道上报 wc.missing-part)。

data-scope="cascader"root · label · trigger · value-text · indicator · clear-trigger · positioner · content · column · item · item-text · item-indicator

Props

属性类型必填说明
collectionCascaderNode[]树数据,层级元信息与显示文本的唯一事实源。缺省为空树。
valueCascaderValue选中路径。给定即受控:cell 直读 prop,写只发 onValueChange 不落内部值。 单条路径是简写,内部一律归一成路径集合。
defaultValueCascaderValue
openboolean展开态。给定即受控:内部不再自改,只发 onOpenChange。
defaultOpenboolean
expandTriggerCascaderExpandTrigger子列由什么展开,默认 click。
changeOnSelectboolean中间层(分支)也能落值。关掉时点分支只展开子列,不改选中值。
multipleboolean多选:选中是路径集合,选中后浮层不收起、焦点留在列里以便接着挑。
cascadeboolean多选下父子级联勾选:点分支整枝传导、子全勾父勾、部分勾中半选, 禁用子树整棵冻结。默认 false(按路径原样翻转);单选下无效。
checkedStrategyCascadeStrategy级联下对外值的收敛策略,默认 child(只收叶);parent = 最高整枝,all = 全部勾中节点。
disabledboolean整个控件禁用:trigger 用原生 disabled,浮层展不开。
readOnlyboolean只读:浮层照常展开与浏览,但选中值改不动、也清不掉。
invalidboolean校验失败:trigger 报 aria-invalid,各角色节点带 data-invalid。
variantControlVariant形态:outline / subtle / ghost,决定触发框的描边与底色怎么用。
toneTone语气:brand / neutral / success / warning / danger / info,决定聚焦与选中用哪族颜色。
sizeSize尺寸:sm / md / lg,决定触发框与条目的几何档位。
placeholderstring无选中时 value-text 显示的占位文字。
separatorstring路径回显的连接符,默认 ' / '。
placementPlacement
offsetnumber
loopboolean列内上下键走到首尾是否回绕,默认 true。
dirDirection文字方向,默认 ltr;只对调左右方向键的「进子列/回上一列」语义。
onValueChange(details: CascaderValueChangeDetails) => voidvalue 变化意图回调;受控时是唯一出口,非受控随内部写入一并通知。
onOpenChange(details: CascaderOpenChangeDetails) => voidopen 变化意图回调;受控时是唯一出口,非受控时随内部转移一并通知。

状态机

状态open · closed

事件OPEN · TOGGLE · CLOSE · CONTROLLED.OPEN · CONTROLLED.CLOSE · ITEM.FOCUS · ITEM.EXPAND · ITEM.LOST · ITEM.SELECT · VALUE.SET · VALUE.CLEAR · PATH.SET

判据isOpenControlled · isMultiple · staysOpenOnSelect

connect API

useCascader 产出的对象。getXxxProps() 铺到对应部件的宿主元素上,其余是可读状态与操作入口。

成员类型说明
openboolean
collectionreadonly CascaderNode[]作者给的原始树数据。
columnsreadonly CascaderColumn[]当下并排开着的列(含每列的条目):列数 = 展开路径走得通的段数 + 1。
levelsreadonly CascaderLevel[]按深度摊开的静态列,与展开路径无关;不该露面的条目由连接层加 hidden 收起。
valuestring[][]选中路径集合;单选下长度 ≤ 1,形状不随模式变。
valuePathstring[] | null单选便利读法:选中的那一条路径,无选中时为 null。
valueTextstring | null选中路径的显示文字(整条路径用分隔符连起来;多选各条之间用逗号);无选中时为 null。
displayTextstringvalue-text 实际显示的文字:有选中取路径文本,否则取 placeholder。
activePathstring[]展开路径:并排开着哪几列由它决定。
focusedPathstring[] | null焦点锚点;收起、或它已不在任何可见列里时为 null。
multipleboolean
disabledboolean
readOnlyboolean
invalidboolean
canClearboolean清空按钮此刻可不可按。
isSelected(value: string) => boolean该条目是否是某条选中路径的末项。
isIndeterminate(value: string) => boolean级联模式下该分支是否半选(有效叶后代有勾有不勾);非级联恒 false。
isActive(value: string) => boolean该条目是否落在展开路径上(它的子列开着,或它自己就是最后一站)。
isVisible(value: string) => boolean该条目此刻是否落在某个可见列里。
setOpen(next: boolean) => void
setValue(next: string[][]) => void
setActivePath(next: string[]) => void
select(path: string[]) => void选中一条路径,与点条目同一语义(分支是否落值仍看 changeOnSelect)。
clear() => void
getRootProps() => T['element']
getLabelProps() => T['element']
getTriggerProps() => T['button']
getValueTextProps() => T['element']
getIndicatorProps() => T['element']
getClearTriggerProps() => T['button']
getPositionerProps() => T['element']
getContentProps() => T['element']
getColumnProps(props: CascaderColumnProps) => T['element']
getItemProps(props: CascaderItemProps) => T['element']
getItemTextProps(props: CascaderItemProps) => T['element']
getItemIndicatorProps(props: CascaderItemProps) => T['element']

键盘

规格出处:W3C APG

按键生效条件行为
Enter / Spaceclosed, focus in trigger展开浮层并把焦点落到选中路径的末项(无选中或它已禁用则落该列首个可用条目)
ArrowDownclosed, focus in trigger展开浮层并把焦点落到选中条目在它那一列里的下一个可用条目
ArrowUpclosed, focus in trigger展开浮层并把焦点落到选中条目在它那一列里的上一个可用条目
ArrowDownopen, focus in content焦点移到当前列的下一个条目(禁用条目跳过;loop 默认开,末项回绕到首项);别的列不动
ArrowUpopen, focus in content焦点移到当前列的上一个条目(禁用条目跳过;loop 默认开,首项回绕到末项)
Homeopen, focus in content焦点移到当前列的首个可用条目
Endopen, focus in content焦点移到当前列的末个可用条目
ArrowRightopen, 焦点条目有子节点(dir=rtl 时改由 ArrowLeft 承担)焦点移进右边那一列的首个可用条目;叶子上什么都不做且不吞键
ArrowLeftopen, 焦点不在根列(dir=rtl 时改由 ArrowRight 承担)焦点退回上一列的父条目,当前这一列随之收起;根列上什么都不做且不吞键
Enter / Spaceopen, 焦点条目未禁用叶子:落值并收起浮层、焦点归还 trigger。分支:展开它的子列且浮层不收起,changeOnSelect 打开时同时落值
Escapeopen收起浮层并把焦点归还 trigger,选中值不变
Tab / Shift+Tabopen收起浮层,焦点不归还 trigger,按 Tab 序列自然离开

Released under The MIT License