For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/llms-full.txt, and this page is available as Markdown at https://ifhover.github.io/leaf-ui/v/0.6.0/components/cascader.md.
  • 简体中文
  • Cascader 级联选择

    用于逐级选择地区、分类等有层级关系的选项。

    基础选择

    children 定义子选项。点击父项展开下一列,点击末级选项确认完整路径;disabled 可以禁用一个分支。

    basic.tsx
    import { Cascader, Form, FormField } from '@ifhover/leaf-ui';
    
    const options = [
      {
        value: 'design',
        label: '设计',
        children: [
          { value: 'interface', label: '界面设计' },
          { value: 'brand', label: '品牌设计' },
        ],
      },
      {
        value: 'engineering',
        label: '工程',
        children: [
          { value: 'frontend', label: '前端开发' },
          { value: 'backend', label: '后端开发' },
        ],
      },
      { value: 'archived', label: '归档分类', disabled: true },
    ];
    
    export function CascaderBasic() {
      return (
        <Form layout="vertical">
          <FormField label="项目分类">
            <Cascader aria-label="项目分类" options={options} placeholder="选择项目分类" />
          </FormField>
          <FormField label="默认分类">
            <Cascader aria-label="默认分类" options={options} defaultValue={['design', 'interface']} />
          </FormField>
          <FormField label="禁用分类">
            <Cascader aria-label="禁用分类" options={options} disabled />
          </FormField>
        </Form>
      );
    }
    

    受控路径

    value 是从根节点到末级节点的 value 数组,onChange 同时提供完整的选项对象路径。切换父项后会清除旧分支的后续选择。

    选中路径:zhejiang → hangzhou → xihu
    controlled.tsx
    import { Cascader, Form, FormField, Text } from '@ifhover/leaf-ui';
    
    import { useState } from 'react';
    
    import { regions } from './options';
    
    export function CascaderControlled() {
      const [value, setValue] = useState<string[]>(['zhejiang', 'hangzhou', 'xihu']);
      return (
        <Form layout="vertical">
          <FormField label="收货地区">
            <Cascader aria-label="收货地区" options={regions} value={value} onChange={setValue} />
          </FormField>
          <Text tone="muted">选中路径:{value.join(' → ') || '未选择'}</Text>
        </Form>
      );
    }
    

    示例使用的地区选项:

    options.ts
    import type { CascaderOption } from '@ifhover/leaf-ui';
    
    export const regions: CascaderOption[] = [
      {
        value: 'zhejiang',
        label: '浙江',
        children: [
          {
            value: 'hangzhou',
            label: '杭州',
            children: [
              { value: 'xihu', label: '西湖区' },
              { value: 'yuhang', label: '余杭区' },
            ],
          },
          { value: 'ningbo', label: '宁波', children: [{ value: 'haishu', label: '海曙区' }] },
        ],
      },
      {
        value: 'jiangsu',
        label: '江苏',
        children: [
          { value: 'nanjing', label: '南京', children: [{ value: 'gulou', label: '鼓楼区' }] },
          { value: 'suzhou', label: '苏州', children: [{ value: 'gusu', label: '姑苏区' }] },
        ],
      },
      { value: 'archived', label: '归档地区', disabled: true },
    ];
    

    搜索、多选与异步加载

    搜索、多选与选择中间层
    懒加载与刷新缓存
    capabilities.tsx
    import type { CascaderOption } from '@ifhover/leaf-ui';
    
    import { Button, Cascader, Flex, Space, Text } from '@ifhover/leaf-ui';
    
    import { useCallback, useState } from 'react';
    
    const options = [
      {
        value: 'product',
        label: 'Product',
        children: [
          { value: 'ui', label: 'UI' },
          { value: 'web', label: 'Web' },
        ],
      },
      { value: 'team', label: 'Team', children: [{ value: 'design', label: 'Design' }] },
    ];
    
    const lazy: CascaderOption[] = [{ value: 'remote', label: 'Remote', isLeaf: false }];
    
    export function Capabilities() {
      const [version, setVersion] = useState(0);
      const load = useCallback(async (option: CascaderOption, signal: AbortSignal) => {
        await new Promise<void>((resolve, reject) => {
          const timer = setTimeout(resolve, 350);
          signal.addEventListener(
            'abort',
            () => {
              clearTimeout(timer);
              reject(signal.reason);
            },
            { once: true },
          );
        });
        return [{ value: `${option.value}-child`, label: 'Loaded item', isLeaf: true }];
      }, []);
      return (
        <Space direction="vertical" align="stretch">
          <Flex direction="column" gap="sm" align="center">
            <Text>
              {'搜索、多选与选择中间层'}
            </Text>
            <Cascader options={options} showSearch multiple changeOnSelect />
          </Flex>
          <Flex direction="column" gap="sm" align="center">
            <Text>{'懒加载与刷新缓存'}</Text>
            <Cascader options={lazy} loadData={load} cacheKey={version} allowClear />
          </Flex>
          <Button variant="outline" onClick={() => setVersion(version + 1)}>
            {'刷新数据'}
          </Button>
        </Space>
      );
    }
    

    单行多选

    设置 tagWrap={false} 后,已选项始终展示在一行内。长文字自动省略,放不下的选项合并为 +N;空间很窄时只显示数量,打开浮层可查看和修改选择。maxTagCount 可进一步限制标签数量,maxTagCount="responsive" 也会启用单行自动折叠。

    single-line.tsx
    import { Cascader } from '@ifhover/leaf-ui';
    
    const options = [
      {
        value: 'product',
        label: '产品团队',
        children: [
          { value: 'design', label: '产品体验设计' },
          { value: 'web', label: '前端开发' },
          { value: 'mobile', label: '移动端开发' },
        ],
      },
    ];
    
    export function SingleLine() {
      return (
        <Cascader
          aria-label="产品团队"
          multiple
          showSearch
          tagWrap={false}
          options={options}
          defaultValue={[
            ['product', 'design'],
            ['product', 'web'],
            ['product', 'mobile'],
          ]}
        />
      );
    }
    

    Cascader API

    属性类型默认值说明
    popupPlacement'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end'—浮层相对触发控件的位置。
    popupClassNamestring—浮层的自定义类名。
    popupStyleCSSProperties—浮层的自定义样式。
    popupRender(content: React.ReactNode) => React.ReactNode—包装或补充面板内容,保留传入的内容以维持交互。
    getPopupContainer() => Element | DocumentFragment—返回浮层的挂载容器,也可返回 ShadowRoot。
    optionsreadonly CascaderOption[]必填必需。层级选项列表
    size'sm' | 'md' | 'lg''md'选择器尺寸
    status'error' | 'warning'—校验状态
    placeholderstring'请选择'未选择时的提示文字
    namestring—字段名 / 关联的表单 ID
    requiredbooleanfalse要求整体值非空,复合控件只校验一次。
    allowClearbooleantrue清除后返回两个空数组
    onOpenChange(open: boolean) => void—面板展开或收起
    openboolean—控制面板是否展开。
    defaultOpenboolean—面板初始展开状态。
    readOnlyboolean—锁定业务值,禁止输入、选择、清除和删除。
    showSearchboolean—启用搜索输入。
    changeOnSelectboolean—允许选择中间层级。
    displayRender(labels: ReactNode[], selectedOptions: CascaderOption[]) => ReactNode—自定义路径的显示内容。
    optionRender(option: CascaderOption) => ReactNode—自定义选项内容。
    loadData(option: CascaderOption, signal: AbortSignal) => Promise<readonly CascaderOption[]>—异步加载子节点;应响应 AbortSignal。
    onLoadError(error: unknown, option: CascaderOption) => void—加载失败时调用,可展示重试提示。
    cacheKeystring | number—数据版本改变时清空懒加载缓存,并取消旧请求。
    tagWrapbooleantrue允许多选标签换行;false 单行显示并自动折叠溢出项。
    maxTagCountnumber | 'responsive'—最多展示的标签数;responsive 根据可用宽度自动折叠。
    multiplefalse | truefalse启用多选;value 和回调的类型随之变化。
    valuereadonly string[] | readonly (readonly string[])[][]受控路径 / 非受控初始路径
    defaultValuereadonly string[] | readonly (readonly string[])[][]受控路径 / 非受控初始路径
    onChange((value: string[], selectedOptions: CascaderOption[]) => void) | ((value: string[][], selectedOptions: CascaderOption[][]) => void)—末级选择完成或清除时触发
    disabledbooleanfalse禁用交互。
    formstring—关联的原生表单 ID。
    refRef<HTMLButtonElement>—触发按钮引用

    同一层内的 value 应唯一,传入路径应完整且存在于 options 中。其余原生 button 属性和 aria-* 透传至触发按钮;className / style 作用于外层容器。

    类型

    CascaderProps 用于定义组件属性。单独组装层级选项时,可以使用 CascaderOption:

    import type { CascaderProps, CascaderOption, ControlSize, ControlStatus } from '@ifhover/leaf-ui';
    
    const options: CascaderOption[] = [
      {
        label: '浙江',
        value: 'zhejiang',
        children: [{ label: '杭州', value: 'hangzhou' }],
      },
    ];

    CascaderOption

    属性类型默认值说明
    valuestring必填选项值,同一层内应唯一
    labelstring必填选项文字
    disabledbooleanfalse禁用该选项及其子级
    childrenreadonly CascaderOption[]—子选项;没有子选项时可确认选择

    表单与键盘

    设置 name 后,FormData 的值为 JSON 数组字符串,例如 ["zhejiang","hangzhou","xihu"],清除后为空字符串。可用 JSON.parse 读取路径。非受控组件支持表单 reset,受控组件需同步重置自己的状态。

    Enter、空格或 ↓ 打开面板,↑ / ↓ 在列内移动,Home / End 移至首尾,→ 展开子级,← 返回上一级,Enter 选择。Tab 在各列之间移动,离开面板时聚焦表单中的后续控件;Escape 收起并聚焦触发按钮。关闭时未确认的路径不会提交。

    面板沿用局部主题,较深层级可以横向滚动查看。为控件提供 label 或 aria-label。

    CascaderOption

    属性类型默认值说明
    valuestring—必需。受控值。
    labelReactNode—必需。展示文字或内容。
    searchLabelstring—搜索时使用的纯文本。
    isLeafboolean—明确指定是否为叶子节点,配合异步加载使用。
    disabledboolean—禁用交互。
    childrenreadonly CascaderOption[]—子内容;嵌套数据类型表示子节点。

    CascaderFieldNames

    属性类型默认值说明
    valuestring—受控值。
    labelstring—展示文字或内容。
    childrenstring—子内容;嵌套数据类型表示子节点。
    disabledstring—禁用交互。
    isLeafstring—明确指定是否为叶子节点,配合异步加载使用。