Cascader级联选择 - 图1

Cascader 级联选择

级联选择框。

何时使用

  • 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。
  • 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。
  • 比起 Select 组件,可以在同一个浮层中完成选择,有较好的体验。

代码演示

Cascader级联选择 - 图2

基本用法

省市区级联。

  1. <template>
  2. <a-cascader v-model:value="value" :options="options" placeholder="Please select" />
  3. </template>
  4. <script lang="ts">
  5. import { defineComponent, ref } from 'vue';
  6. interface Option {
  7. value: string;
  8. label: string;
  9. children?: Option[];
  10. }
  11. const options: Option[] = [
  12. {
  13. value: 'zhejiang',
  14. label: 'Zhejiang',
  15. children: [
  16. {
  17. value: 'hangzhou',
  18. label: 'Hangzhou',
  19. children: [
  20. {
  21. value: 'xihu',
  22. label: 'West Lake',
  23. },
  24. ],
  25. },
  26. ],
  27. },
  28. {
  29. value: 'jiangsu',
  30. label: 'Jiangsu',
  31. children: [
  32. {
  33. value: 'nanjing',
  34. label: 'Nanjing',
  35. children: [
  36. {
  37. value: 'zhonghuamen',
  38. label: 'Zhong Hua Men',
  39. },
  40. ],
  41. },
  42. ],
  43. },
  44. ];
  45. export default defineComponent({
  46. setup() {
  47. return {
  48. value: ref<string[]>([]),
  49. options,
  50. };
  51. },
  52. });
  53. </script>

Cascader级联选择 - 图3

移入展开

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

  1. <template>
  2. <a-cascader
  3. v-model:value="value"
  4. :options="options"
  5. :display-render="displayRender"
  6. expand-trigger="hover"
  7. placeholder="Please select"
  8. />
  9. </template>
  10. <script lang="ts">
  11. import { defineComponent, ref } from 'vue';
  12. interface Option {
  13. value: string;
  14. label: string;
  15. children?: Option[];
  16. }
  17. const options: Option[] = [
  18. {
  19. value: 'zhejiang',
  20. label: 'Zhejiang',
  21. children: [
  22. {
  23. value: 'hangzhou',
  24. label: 'Hangzhou',
  25. children: [
  26. {
  27. value: 'xihu',
  28. label: 'West Lake',
  29. },
  30. ],
  31. },
  32. ],
  33. },
  34. {
  35. value: 'jiangsu',
  36. label: 'Jiangsu',
  37. children: [
  38. {
  39. value: 'nanjing',
  40. label: 'Nanjing',
  41. children: [
  42. {
  43. value: 'zhonghuamen',
  44. label: 'Zhong Hua Men',
  45. },
  46. ],
  47. },
  48. ],
  49. },
  50. ];
  51. export default defineComponent({
  52. setup() {
  53. const displayRender = ({ labels }: { labels: string[] }) => {
  54. return labels[labels.length - 1];
  55. };
  56. return {
  57. value: ref<string[]>([]),
  58. options,
  59. displayRender,
  60. };
  61. },
  62. });
  63. </script>

Cascader级联选择 - 图4

选择即改变

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

  1. <template>
  2. <a-cascader v-model:value="value" :options="options" change-on-select />
  3. </template>
  4. <script lang="ts">
  5. import { defineComponent, ref } from 'vue';
  6. interface Option {
  7. value: string;
  8. label: string;
  9. children?: Option[];
  10. }
  11. const options: Option[] = [
  12. {
  13. value: 'zhejiang',
  14. label: 'Zhejiang',
  15. children: [
  16. {
  17. value: 'hangzhou',
  18. label: 'Hangzhou',
  19. children: [
  20. {
  21. value: 'xihu',
  22. label: 'West Lake',
  23. },
  24. ],
  25. },
  26. ],
  27. },
  28. {
  29. value: 'jiangsu',
  30. label: 'Jiangsu',
  31. children: [
  32. {
  33. value: 'nanjing',
  34. label: 'Nanjing',
  35. children: [
  36. {
  37. value: 'zhonghuamen',
  38. label: 'Zhong Hua Men',
  39. },
  40. ],
  41. },
  42. ],
  43. },
  44. ];
  45. export default defineComponent({
  46. setup() {
  47. return {
  48. value: ref<string[]>([]),
  49. options,
  50. };
  51. },
  52. });
  53. </script>

Zhejiang /Hangzhou /West Lake ( 752100 ) Cascader级联选择 - 图5Cascader级联选择 - 图6

自定义已选项

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

  1. <template>
  2. <a-cascader v-model:value="value" :options="options" style="width: 100%">
  3. <template #displayRender="{ labels, selectedOptions }">
  4. <span v-for="(label, index) in labels" :key="selectedOptions[index].value">
  5. <span v-if="index === labels.length - 1">
  6. {{ label }} (
  7. <a @click="e => handleAreaClick(e, label, selectedOptions[index])">
  8. {{ selectedOptions[index].code }}
  9. </a>
  10. )
  11. </span>
  12. <span v-else>{{ label }} /</span>
  13. </span>
  14. </template>
  15. </a-cascader>
  16. </template>
  17. <script lang="ts">
  18. import { defineComponent, ref } from 'vue';
  19. interface Option {
  20. value: string;
  21. label: string;
  22. children?: Option[];
  23. code?: number;
  24. [key: string]: any;
  25. }
  26. const options: Option[] = [
  27. {
  28. value: 'zhejiang',
  29. label: 'Zhejiang',
  30. children: [
  31. {
  32. value: 'hangzhou',
  33. label: 'Hangzhou',
  34. children: [
  35. {
  36. value: 'xihu',
  37. label: 'West Lake',
  38. code: 752100,
  39. },
  40. ],
  41. },
  42. ],
  43. },
  44. {
  45. value: 'jiangsu',
  46. label: 'Jiangsu',
  47. children: [
  48. {
  49. value: 'nanjing',
  50. label: 'Nanjing',
  51. children: [
  52. {
  53. value: 'zhonghuamen',
  54. label: 'Zhong Hua Men',
  55. code: 453400,
  56. },
  57. ],
  58. },
  59. ],
  60. },
  61. ];
  62. export default defineComponent({
  63. setup() {
  64. const handleAreaClick = (e: Event, label: string, option: Option) => {
  65. e.stopPropagation();
  66. console.log('clicked', label, option);
  67. };
  68. return {
  69. value: ref<string[]>(['zhejiang', 'hangzhou', 'xihu']),
  70. options,
  71. handleAreaClick,
  72. };
  73. },
  74. });
  75. </script>

Cascader级联选择 - 图7

动态加载选项

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

注意:loadDatashowSearch 无法一起使用。

  1. <template>
  2. <a-cascader
  3. v-model:value="value"
  4. :options="options"
  5. :load-data="loadData"
  6. placeholder="Please select"
  7. change-on-select
  8. />
  9. </template>
  10. <script lang="ts">
  11. import { defineComponent, ref } from 'vue';
  12. interface Option {
  13. value: string;
  14. label: string;
  15. loading?: boolean;
  16. isLeaf?: boolean;
  17. children?: Option[];
  18. }
  19. export default defineComponent({
  20. setup() {
  21. const options = ref<Option[]>([
  22. {
  23. value: 'zhejiang',
  24. label: 'Zhejiang',
  25. isLeaf: false,
  26. },
  27. {
  28. value: 'jiangsu',
  29. label: 'Jiangsu',
  30. isLeaf: false,
  31. },
  32. ]);
  33. const loadData = (selectedOptions: Option[]) => {
  34. const targetOption = selectedOptions[selectedOptions.length - 1];
  35. targetOption.loading = true;
  36. // load options lazily
  37. setTimeout(() => {
  38. targetOption.loading = false;
  39. targetOption.children = [
  40. {
  41. label: `${targetOption.label} Dynamic 1`,
  42. value: 'dynamic1',
  43. },
  44. {
  45. label: `${targetOption.label} Dynamic 2`,
  46. value: 'dynamic2',
  47. },
  48. ];
  49. options.value = [...options.value];
  50. }, 1000);
  51. };
  52. return {
  53. value: ref<string[]>([]),
  54. options,
  55. loadData,
  56. };
  57. },
  58. });
  59. </script>

Cascader级联选择 - 图8ab

后缀图标

自定义后缀图标

  1. <template>
  2. <a-cascader
  3. v-model:value="value1"
  4. style="margin-top: 1rem"
  5. :options="options"
  6. placeholder="Please select"
  7. >
  8. <template #suffixIcon><smile-outlined class="test" /></template>
  9. </a-cascader>
  10. <a-cascader
  11. v-model:value="value2"
  12. suffix-icon="ab"
  13. style="margin-top: 1rem"
  14. :options="options"
  15. placeholder="Please select"
  16. />
  17. </template>
  18. <script lang="ts">
  19. import { SmileOutlined } from '@ant-design/icons-vue';
  20. import { defineComponent, ref } from 'vue';
  21. interface Option {
  22. value: string;
  23. label: string;
  24. children?: Option[];
  25. }
  26. const options: Option[] = [
  27. {
  28. value: 'zhejiang',
  29. label: 'Zhejiang',
  30. children: [
  31. {
  32. value: 'hangzhou',
  33. label: 'Hangzhou',
  34. children: [
  35. {
  36. value: 'xihu',
  37. label: 'West Lake',
  38. },
  39. ],
  40. },
  41. ],
  42. },
  43. {
  44. value: 'jiangsu',
  45. label: 'Jiangsu',
  46. children: [
  47. {
  48. value: 'nanjing',
  49. label: 'Nanjing',
  50. children: [
  51. {
  52. value: 'zhonghuamen',
  53. label: 'Zhong Hua Men',
  54. },
  55. ],
  56. },
  57. ],
  58. },
  59. ];
  60. export default defineComponent({
  61. components: {
  62. SmileOutlined,
  63. },
  64. setup() {
  65. return {
  66. value1: ref<string[]>([]),
  67. value2: ref<string[]>([]),
  68. options,
  69. };
  70. },
  71. });
  72. </script>

Unselect Change city

可以自定义显示

切换按钮和结果分开。

  1. <template>
  2. <span>
  3. {{ text }} &nbsp;
  4. <a-cascader v-model:value="value" :options="options" @change="onChange">
  5. <a href="#">Change city</a>
  6. </a-cascader>
  7. </span>
  8. </template>
  9. <script lang="ts">
  10. import { defineComponent, ref } from 'vue';
  11. interface Option {
  12. value: string;
  13. label: string;
  14. children?: Option[];
  15. code?: number;
  16. [key: string]: any;
  17. }
  18. const options: Option[] = [
  19. {
  20. value: 'zhejiang',
  21. label: 'Zhejiang',
  22. children: [
  23. {
  24. value: 'hangzhou',
  25. label: 'Hangzhou',
  26. children: [
  27. {
  28. value: 'xihu',
  29. label: 'West Lake',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. {
  36. value: 'jiangsu',
  37. label: 'Jiangsu',
  38. children: [
  39. {
  40. value: 'nanjing',
  41. label: 'Nanjing',
  42. children: [
  43. {
  44. value: 'zhonghuamen',
  45. label: 'Zhong Hua Men',
  46. },
  47. ],
  48. },
  49. ],
  50. },
  51. ];
  52. export default defineComponent({
  53. setup() {
  54. const value = ref<string[]>([]);
  55. const text = ref<string>('Unselect');
  56. const onChange = (value: string, selectedOptions: Option[]) => {
  57. text.value = selectedOptions.map(o => o.label).join(', ');
  58. };
  59. return {
  60. value,
  61. text,
  62. options,
  63. onChange,
  64. };
  65. },
  66. });
  67. </script>

Cascader级联选择 - 图9

禁用选项

通过指定 options 里的 disabled 字段。

  1. <template>
  2. <a-cascader v-model:value="value" :options="options" />
  3. </template>
  4. <script lang="ts">
  5. import { defineComponent, ref } from 'vue';
  6. interface Option {
  7. value: string;
  8. label: string;
  9. disabled?: boolean;
  10. children?: Option[];
  11. code?: number;
  12. [key: string]: any;
  13. }
  14. const options: Option[] = [
  15. {
  16. value: 'zhejiang',
  17. label: 'Zhejiang',
  18. children: [
  19. {
  20. value: 'hangzhou',
  21. label: 'Hangzhou',
  22. children: [
  23. {
  24. value: 'xihu',
  25. label: 'West Lake',
  26. },
  27. ],
  28. },
  29. ],
  30. },
  31. {
  32. value: 'jiangsu',
  33. label: 'Jiangsu',
  34. disabled: true,
  35. children: [
  36. {
  37. value: 'nanjing',
  38. label: 'Nanjing',
  39. children: [
  40. {
  41. value: 'zhonghuamen',
  42. label: 'Zhong Hua Men',
  43. },
  44. ],
  45. },
  46. ],
  47. },
  48. ];
  49. export default defineComponent({
  50. setup() {
  51. return {
  52. value: ref<string[]>([]),
  53. options,
  54. };
  55. },
  56. });
  57. </script>

Cascader级联选择 - 图10

Cascader级联选择 - 图11

Cascader级联选择 - 图12

大小

不同大小的级联选择器。

  1. <template>
  2. <a-cascader v-model:value="value" size="large" :options="options" />
  3. <br />
  4. <br />
  5. <a-cascader v-model:value="value" :options="options" />
  6. <br />
  7. <br />
  8. <a-cascader v-model:value="value" size="small" :options="options" />
  9. <br />
  10. <br />
  11. </template>
  12. <script lang="ts">
  13. import { defineComponent, ref } from 'vue';
  14. interface Option {
  15. value: string;
  16. label: string;
  17. children?: Option[];
  18. }
  19. const options: Option[] = [
  20. {
  21. value: 'zhejiang',
  22. label: 'Zhejiang',
  23. children: [
  24. {
  25. value: 'hangzhou',
  26. label: 'Hangzhou',
  27. children: [
  28. {
  29. value: 'xihu',
  30. label: 'West Lake',
  31. },
  32. ],
  33. },
  34. ],
  35. },
  36. {
  37. value: 'jiangsu',
  38. label: 'Jiangsu',
  39. children: [
  40. {
  41. value: 'nanjing',
  42. label: 'Nanjing',
  43. children: [
  44. {
  45. value: 'zhonghuamen',
  46. label: 'Zhong Hua Men',
  47. },
  48. ],
  49. },
  50. ],
  51. },
  52. ];
  53. export default defineComponent({
  54. setup() {
  55. return {
  56. value: ref<string[]>([]),
  57. options,
  58. };
  59. },
  60. });
  61. </script>

Cascader级联选择 - 图13

搜索

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

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

  1. <template>
  2. <a-cascader
  3. v-model:value="value"
  4. :options="options"
  5. :show-search="{ filter }"
  6. placeholder="Please select"
  7. />
  8. </template>
  9. <script lang="ts">
  10. import { defineComponent, ref } from 'vue';
  11. interface Option {
  12. value: string;
  13. label: string;
  14. disabled?: boolean;
  15. children?: Option[];
  16. }
  17. const options: Option[] = [
  18. {
  19. value: 'zhejiang',
  20. label: 'Zhejiang',
  21. children: [
  22. {
  23. value: 'hangzhou',
  24. label: 'Hangzhou',
  25. children: [
  26. {
  27. value: 'xihu',
  28. label: 'West Lake',
  29. },
  30. {
  31. value: 'xiasha',
  32. label: 'Xia Sha',
  33. disabled: true,
  34. },
  35. ],
  36. },
  37. ],
  38. },
  39. {
  40. value: 'jiangsu',
  41. label: 'Jiangsu',
  42. children: [
  43. {
  44. value: 'nanjing',
  45. label: 'Nanjing',
  46. children: [
  47. {
  48. value: 'zhonghuamen',
  49. label: 'Zhong Hua men',
  50. },
  51. ],
  52. },
  53. ],
  54. },
  55. ];
  56. export default defineComponent({
  57. setup() {
  58. const filter = (inputValue: string, path: Option[]) => {
  59. return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
  60. };
  61. return {
  62. value: ref<string[]>([]),
  63. options,
  64. filter,
  65. };
  66. },
  67. });
  68. </script>

Cascader级联选择 - 图14

自定义字段名

自定义字段名。

  1. <template>
  2. <a-cascader
  3. v-model:value="value"
  4. :field-names="{ label: 'name', value: 'code', children: 'items' }"
  5. :options="options"
  6. placeholder="Please select"
  7. />
  8. </template>
  9. <script lang="ts">
  10. import { defineComponent, ref } from 'vue';
  11. interface Option {
  12. code: string;
  13. name: string;
  14. disabled?: boolean;
  15. items?: Option[];
  16. [key: string]: any;
  17. }
  18. const options: Option[] = [
  19. {
  20. code: 'zhejiang',
  21. name: 'Zhejiang',
  22. items: [
  23. {
  24. code: 'hangzhou',
  25. name: 'Hangzhou',
  26. items: [
  27. {
  28. code: 'xihu',
  29. name: 'West Lake',
  30. },
  31. ],
  32. },
  33. ],
  34. },
  35. {
  36. code: 'jiangsu',
  37. name: 'Jiangsu',
  38. items: [
  39. {
  40. code: 'nanjing',
  41. name: 'Nanjing',
  42. items: [
  43. {
  44. code: 'zhonghuamen',
  45. name: 'Zhong Hua Men',
  46. },
  47. ],
  48. },
  49. ],
  50. },
  51. ];
  52. export default defineComponent({
  53. setup() {
  54. return {
  55. value: ref<string[]>([]),
  56. options,
  57. };
  58. },
  59. });
  60. </script>

API

  1. <a-cascader :options="options" v-model:value="value" />
参数说明类型默认值
allowClear是否支持清除booleantrue
autofocus自动获取焦点booleanfalse
changeOnSelect当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示booleanfalse
defaultValue默认的选中项string[] | number[][]
disabled禁用booleanfalse
displayRender选择后展示的渲染函数,可使用 #displayRender=”{labels, selectedOptions}”({labels, selectedOptions}) => VNodelabels => labels.join(‘ / ‘)
expandTrigger次级菜单的展开方式,可选 ‘click’ 和 ‘hover’string‘click’
fieldNames自定义 options 中 label name children 的字段object{ label: ‘label’, value: ‘value’, children: ‘children’ }
getPopupContainer菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。Function(triggerNode)() => document.body
loadData用于动态加载选项,无法与 showSearch 一起使用(selectedOptions) => void-
notFoundContent当下拉列表为空时显示的内容string‘Not Found’
options可选项数据源Option[]-
placeholder输入框占位文本string‘请选择’
popupClassName自定义浮层类名string-
popupStyle自定义浮层样式object{}
popupPlacement浮层预设位置:bottomLeft bottomRight topLeft topRightEnumbottomLeft
popupVisible控制浮层显隐boolean-
showSearch在选择框中显示搜索框boolean | objectfalse
size输入框大小,可选 large default smallstringdefault
suffixIcon自定义的选择框后缀图标string | VNode | slot-
value(v-model)指定选中项string[] | number[]-

showSearch

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

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

事件

事件名称说明回调参数版本
change选择完成后的回调(value, selectedOptions) => void-
popupVisibleChange显示/隐藏浮层的回调(value) => void-
search输入框变化时的回调(value) => void-

Option

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

方法

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

注意,如果需要获得中国省市区数据,可以参考 react 组件的实现 china-division