Cascader级联选择

级联选择框。

何时使用

  • 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。

  • 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。

  • 比起 Select 组件,可以在同一个浮层中完成选择,有较好的体验。

代码演示

Cascader级联选择 - 图1

基本

省市区级联。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. children: [
  23. {
  24. value: 'nanjing',
  25. label: 'Nanjing',
  26. children: [
  27. {
  28. value: 'zhonghuamen',
  29. label: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function onChange(value) {
  37. console.log(value);
  38. }
  39. ReactDOM.render(
  40. <Cascader options={options} onChange={onChange} placeholder="Please select" />,
  41. mountNode,
  42. );

Cascader级联选择 - 图2

可以自定义显示

切换按钮和结果分开。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. },
  11. ],
  12. },
  13. {
  14. value: 'jiangsu',
  15. label: 'Jiangsu',
  16. children: [
  17. {
  18. value: 'nanjing',
  19. label: 'Nanjing',
  20. },
  21. ],
  22. },
  23. ];
  24. class CitySwitcher extends React.Component {
  25. state = {
  26. text: 'Unselect',
  27. };
  28. onChange = (value, selectedOptions) => {
  29. this.setState({
  30. text: selectedOptions.map(o => o.label).join(', '),
  31. });
  32. };
  33. render() {
  34. return (
  35. <span>
  36. {this.state.text}
  37. &nbsp;
  38. <Cascader options={options} onChange={this.onChange}>
  39. <a href="#">Change city</a>
  40. </Cascader>
  41. </span>
  42. );
  43. }
  44. }
  45. ReactDOM.render(<CitySwitcher />, mountNode);

Cascader级联选择 - 图3

禁用选项

通过指定 options 里的 disabled 字段。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. disabled: true,
  23. children: [
  24. {
  25. value: 'nanjing',
  26. label: 'Nanjing',
  27. children: [
  28. {
  29. value: 'zhonghuamen',
  30. label: 'Zhong Hua Men',
  31. },
  32. ],
  33. },
  34. ],
  35. },
  36. ];
  37. function onChange(value) {
  38. console.log(value);
  39. }
  40. ReactDOM.render(<Cascader options={options} onChange={onChange} />, mountNode);

Cascader级联选择 - 图4

大小

不同大小的级联选择器。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. children: [
  23. {
  24. value: 'nanjing',
  25. label: 'Nanjing',
  26. children: [
  27. {
  28. value: 'zhonghuamen',
  29. label: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function onChange(value) {
  37. console.log(value);
  38. }
  39. ReactDOM.render(
  40. <>
  41. <Cascader size="large" options={options} onChange={onChange} />
  42. <br />
  43. <br />
  44. <Cascader options={options} onChange={onChange} />
  45. <br />
  46. <br />
  47. <Cascader size="small" options={options} onChange={onChange} />
  48. <br />
  49. <br />
  50. </>,
  51. mountNode,
  52. );

Cascader级联选择 - 图5

搜索

可以直接搜索选项并选择。

Cascader[showSearch] 暂不支持服务端搜索,更多信息见 #5547

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. {
  16. value: 'xiasha',
  17. label: 'Xia Sha',
  18. disabled: true,
  19. },
  20. ],
  21. },
  22. ],
  23. },
  24. {
  25. value: 'jiangsu',
  26. label: 'Jiangsu',
  27. children: [
  28. {
  29. value: 'nanjing',
  30. label: 'Nanjing',
  31. children: [
  32. {
  33. value: 'zhonghuamen',
  34. label: 'Zhong Hua men',
  35. },
  36. ],
  37. },
  38. ],
  39. },
  40. ];
  41. function onChange(value, selectedOptions) {
  42. console.log(value, selectedOptions);
  43. }
  44. function filter(inputValue, path) {
  45. return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
  46. }
  47. ReactDOM.render(
  48. <Cascader
  49. options={options}
  50. onChange={onChange}
  51. placeholder="Please select"
  52. showSearch={{ filter }}
  53. />,
  54. mountNode,
  55. );

Cascader级联选择 - 图6

自定义字段名

自定义字段名。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. code: 'zhejiang',
  5. name: 'Zhejiang',
  6. items: [
  7. {
  8. code: 'hangzhou',
  9. name: 'Hangzhou',
  10. items: [
  11. {
  12. code: 'xihu',
  13. name: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. code: 'jiangsu',
  21. name: 'Jiangsu',
  22. items: [
  23. {
  24. code: 'nanjing',
  25. name: 'Nanjing',
  26. items: [
  27. {
  28. code: 'zhonghuamen',
  29. name: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function onChange(value) {
  37. console.log(value);
  38. }
  39. ReactDOM.render(
  40. <Cascader
  41. fieldNames={{ label: 'name', value: 'code', children: 'items' }}
  42. options={options}
  43. onChange={onChange}
  44. placeholder="Please select"
  45. />,
  46. mountNode,
  47. );

Cascader级联选择 - 图7

默认值

默认值通过数组的方式指定。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. children: [
  23. {
  24. value: 'nanjing',
  25. label: 'Nanjing',
  26. children: [
  27. {
  28. value: 'zhonghuamen',
  29. label: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function onChange(value) {
  37. console.log(value);
  38. }
  39. ReactDOM.render(
  40. <Cascader
  41. defaultValue={['zhejiang', 'hangzhou', 'xihu']}
  42. options={options}
  43. onChange={onChange}
  44. />,
  45. mountNode,
  46. );

Cascader级联选择 - 图8

移入展开

通过移入展开下级菜单,点击完成选择。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. children: [
  23. {
  24. value: 'nanjing',
  25. label: 'Nanjing',
  26. children: [
  27. {
  28. value: 'zhonghuamen',
  29. label: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function onChange(value) {
  37. console.log(value);
  38. }
  39. // Just show the latest item.
  40. function displayRender(label) {
  41. return label[label.length - 1];
  42. }
  43. ReactDOM.render(
  44. <Cascader
  45. options={options}
  46. expandTrigger="hover"
  47. displayRender={displayRender}
  48. onChange={onChange}
  49. />,
  50. mountNode,
  51. );

Cascader级联选择 - 图9

选择即改变

这种交互允许只选中父级选项。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hanzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. children: [
  23. {
  24. value: 'nanjing',
  25. label: 'Nanjing',
  26. children: [
  27. {
  28. value: 'zhonghuamen',
  29. label: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function onChange(value) {
  37. console.log(value);
  38. }
  39. ReactDOM.render(<Cascader options={options} onChange={onChange} changeOnSelect />, mountNode);

Cascader级联选择 - 图10

自定义已选项

例如给最后一项加上邮编链接。

  1. import { Cascader } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. code: 752100,
  15. },
  16. ],
  17. },
  18. ],
  19. },
  20. {
  21. value: 'jiangsu',
  22. label: 'Jiangsu',
  23. children: [
  24. {
  25. value: 'nanjing',
  26. label: 'Nanjing',
  27. children: [
  28. {
  29. value: 'zhonghuamen',
  30. label: 'Zhong Hua Men',
  31. code: 453400,
  32. },
  33. ],
  34. },
  35. ],
  36. },
  37. ];
  38. function handleAreaClick(e, label, option) {
  39. e.stopPropagation();
  40. console.log('clicked', label, option);
  41. }
  42. const displayRender = (labels, selectedOptions) =>
  43. labels.map((label, i) => {
  44. const option = selectedOptions[i];
  45. if (i === labels.length - 1) {
  46. return (
  47. <span key={option.value}>
  48. {label} (<a onClick={e => handleAreaClick(e, label, option)}>{option.code}</a>)
  49. </span>
  50. );
  51. }
  52. return <span key={option.value}>{label} / </span>;
  53. });
  54. ReactDOM.render(
  55. <Cascader
  56. options={options}
  57. defaultValue={['zhejiang', 'hangzhou', 'xihu']}
  58. displayRender={displayRender}
  59. style={{ width: '100%' }}
  60. />,
  61. mountNode,
  62. );

Cascader级联选择 - 图11

动态加载选项

使用 loadData 实现动态加载选项。

注意:loadDatashowSearch 无法一起使用。

  1. import { Cascader } from 'antd';
  2. const optionLists = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. isLeaf: false,
  7. },
  8. {
  9. value: 'jiangsu',
  10. label: 'Jiangsu',
  11. isLeaf: false,
  12. },
  13. ];
  14. const LazyOptions = () => {
  15. const [options, setOptions] = React.useState(optionLists);
  16. const onChange = (value, selectedOptions) => {
  17. console.log(value, selectedOptions);
  18. };
  19. const loadData = selectedOptions => {
  20. const targetOption = selectedOptions[selectedOptions.length - 1];
  21. targetOption.loading = true;
  22. // load options lazily
  23. setTimeout(() => {
  24. targetOption.loading = false;
  25. targetOption.children = [
  26. {
  27. label: `${targetOption.label} Dynamic 1`,
  28. value: 'dynamic1',
  29. },
  30. {
  31. label: `${targetOption.label} Dynamic 2`,
  32. value: 'dynamic2',
  33. },
  34. ];
  35. setOptions([...options]);
  36. }, 1000);
  37. };
  38. return <Cascader options={options} loadData={loadData} onChange={onChange} changeOnSelect />;
  39. };
  40. ReactDOM.render(<LazyOptions />, mountNode);

Cascader级联选择 - 图12

扩展菜单

使用 dropdownRender 对下拉菜单进行自由扩展。

  1. import { Cascader, Divider } from 'antd';
  2. const options = [
  3. {
  4. value: 'zhejiang',
  5. label: 'Zhejiang',
  6. children: [
  7. {
  8. value: 'hangzhou',
  9. label: 'Hangzhou',
  10. children: [
  11. {
  12. value: 'xihu',
  13. label: 'West Lake',
  14. },
  15. ],
  16. },
  17. ],
  18. },
  19. {
  20. value: 'jiangsu',
  21. label: 'Jiangsu',
  22. children: [
  23. {
  24. value: 'nanjing',
  25. label: 'Nanjing',
  26. children: [
  27. {
  28. value: 'zhonghuamen',
  29. label: 'Zhong Hua Men',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. ];
  36. function dropdownRender(menus) {
  37. return (
  38. <div>
  39. {menus}
  40. <Divider style={{ margin: 0 }} />
  41. <div style={{ padding: 8 }}>The footer is not very short.</div>
  42. </div>
  43. );
  44. }
  45. ReactDOM.render(
  46. <Cascader options={options} dropdownRender={dropdownRender} placeholder="Please select" />,
  47. mountNode,
  48. );

API

  1. <Cascader options={options} onChange={onChange} />
参数说明类型默认值版本
allowClear是否支持清除booleantrue
autoFocus自动获取焦点booleanfalse
bordered是否有边框booleantrue
changeOnSelect当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示booleanfalse
className自定义类名string-
defaultValue默认的选中项string[] | number[][]
disabled禁用booleanfalse
displayRender选择后展示的渲染函数(label, selectedOptions) => ReactNodelabel => label.join(/)
dropdownRender自定义下拉框内容(menus: ReactNode) => ReactNode-4.4.0
expandIcon自定义次级菜单展开图标ReactNode-4.4.0
expandTrigger次级菜单的展开方式,可选 ‘click’ 和 ‘hover’stringclick
fieldNames自定义 options 中 label name children 的字段object{ label: label, value: value, children: children }
getPopupContainer菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。示例function(triggerNode)() => document.body
loadData用于动态加载选项,无法与 showSearch 一起使用(selectedOptions) => void-
notFoundContent当下拉列表为空时显示的内容stringNot Found
options可选项数据源Option[]-
placeholder输入框占位文本string请选择
popupClassName自定义浮层类名string-
popupPlacement浮层预设位置:bottomLeft bottomRight topLeft topRightstringbottomLeft
popupVisible控制浮层显隐boolean-
showSearch在选择框中显示搜索框boolean | Objectfalse
size输入框大小large | middle | small-
style自定义样式CSSProperties-
suffixIcon自定义的选择框后缀图标ReactNode-
value指定选中项string[] | number[]-
onChange选择完成后的回调(value, selectedOptions) => void-
onPopupVisibleChange显示/隐藏浮层的回调(value) => void-

showSearch

showSearch 为对象时,其中的字段:

参数说明类型默认值版本
filter接收 inputValue path 两个参数,当 path 符合筛选条件时,应返回 true,反之则返回 falsefunction(inputValue, path): boolean-
limit搜索结果展示数量number | false50
matchInputWidth搜索结果列表是否与输入框同宽(效果booleantrue
render用于渲染 filter 后的选项function(inputValue, path): ReactNode-
sort用于排序 filter 后的选项function(a, b, inputValue)-

Option

  1. interface Option {
  2. value: string | number;
  3. label?: React.ReactNode;
  4. disabled?: boolean;
  5. children?: Option[];
  6. }

方法

名称描述版本
blur()移除焦点
focus()获取焦点

注意,如果需要获得中国省市区数据,可以参考 china-division