Cascader 级联选择器
当选项有较好的层级结构时,可以使用 Cascader 级联选择器进行查看和选择。
基础用法
有两种触发子级的方式。
通过 options 属性指定选项数组即可渲染出一个级联选择器。 通过 props.expandTrigger 可以定义展开子级菜单的触发方式。
点击触发(默认)
悬停触发
<template>
<div class="m-4">
<p>Child options expand when clicked (default)</p>
<el-cascader v-model="value" :options="options" @change="handleChange" />
</div>
<div class="m-4">
<p>Child options expand when hovered</p>
<el-cascader
v-model="value"
:options="options"
:props="props"
@change="handleChange"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const value = ref([])
const props = {
expandTrigger: 'hover' as const,
}
const handleChange = (value) => {
console.log(value)
}
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
禁用选项
通过在选项对象中设置 disabled 字段来禁用该选项。
在本例中,options 数组的第一个元素包含 disabled: true 字段,因此它被禁用。 默认情况下,Cascader 会检查每个选项对象中的 disabled 字段;如果您使用其他字段名来表示选项是否禁用,可以在 props.disabled 属性中指定(详情请参阅下面的 API 表)。 当然,value、label 和 children 的字段名也可以用同样的方式自定义。
<template>
<el-cascader :options="options" />
</template>
<script lang="ts" setup>
const options = [
{
value: 'guide',
label: 'Guide',
disabled: true,
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
可清空
为 el-cascader 设置 clearable 属性,在选择且悬停时将显示清除图标。
<template>
<el-cascader :options="options" clearable />
</template>
<script lang="ts" setup>
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
自定义清除图标 2.11.0
您可以通过设置 clear-icon 属性来自定义清除图标。
<template>
<el-cascader
:options="options"
clearable
:clear-icon="CloseBold"
placeholder="Custom clear icon"
/>
</template>
<script lang="ts" setup>
import { CloseBold } from '@element-plus/icons-vue'
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
},
],
},
]
</script>
仅显示最后一级
输入框可以只显示最后一级,而不是所有级别。
show-all-levels 属性定义了是否显示所有级别。 如果为 false,则仅显示最后一级。
<template>
<el-cascader :options="options" :show-all-levels="false" />
</template>
<script lang="ts" setup>
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
多选
在标签中添加 :props="props" 并设置数据 props = { multiple: true } 即可开启多选模式。
正确做法
<template>
<el-cascader :props="props" />
</template>
<script lang="ts" setup>
const props = { multiple: true }
</script>错误做法
<template>
<!-- Object literal binging here is invalid syntax for cascader -->
<el-cascader :props="{ multiple: true }" />
</template>使用多选时,默认会显示所有已选标签。 您可以设置 collapse-tags = true 来折叠已选标签。 您可以设置 max-collapse-tags 来显示最大标签数量,默认为 1。 当鼠标悬停在折叠文本上时,可以使用 collapse-tags-tooltip 属性查看它们。
显示所有标签(默认)
折叠标签
折叠标签提示
最大折叠标签数
<template>
<div class="m-4">
<p>Display all tags (default)</p>
<el-cascader :options="options" :props="props" clearable />
</div>
<div class="m-4">
<p>Collapse tags</p>
<el-cascader :options="options" :props="props" collapse-tags clearable />
</div>
<div class="m-4">
<p>Collapse tags tooltip</p>
<el-cascader
:options="options"
:props="props"
collapse-tags
collapse-tags-tooltip
clearable
/>
</div>
<div class="m-4">
<p>Max Collapse Tags</p>
<el-cascader
:options="options"
:props="props"
collapse-tags
collapse-tags-tooltip
:max-collapse-tags="3"
clearable
/>
</div>
</template>
<script lang="ts" setup>
const props = { multiple: true }
const options = [
{
value: 1,
label: 'Asia',
children: [
{
value: 2,
label: 'China',
children: [
{ value: 3, label: 'Beijing' },
{ value: 4, label: 'Shanghai' },
{ value: 5, label: 'Hangzhou' },
],
},
{
value: 6,
label: 'Japan',
children: [
{ value: 7, label: 'Tokyo' },
{ value: 8, label: 'Osaka' },
{ value: 9, label: 'Kyoto' },
],
},
{
value: 10,
label: 'Korea',
children: [
{ value: 11, label: 'Seoul' },
{ value: 12, label: 'Busan' },
{ value: 13, label: 'Taegu' },
],
},
],
},
{
value: 14,
label: 'Europe',
children: [
{
value: 15,
label: 'France',
children: [
{ value: 16, label: 'Paris' },
{ value: 17, label: 'Marseille' },
{ value: 18, label: 'Lyon' },
],
},
{
value: 19,
label: 'UK',
children: [
{ value: 20, label: 'London' },
{ value: 21, label: 'Birmingham' },
{ value: 22, label: 'Manchester' },
],
},
],
},
{
value: 23,
label: 'North America',
children: [
{
value: 24,
label: 'US',
children: [
{ value: 25, label: 'New York' },
{ value: 26, label: 'Los Angeles' },
{ value: 27, label: 'Washington' },
],
},
{
value: 28,
label: 'Canada',
children: [
{ value: 29, label: 'Toronto' },
{ value: 30, label: 'Montreal' },
{ value: 31, label: 'Ottawa' },
],
},
],
},
]
</script>
选择任意一级选项
在单选模式下,只能选择叶子节点,而在多选模式下,选择父节点最终会导致选择叶子节点。 开启该功能后,可以使父子节点解耦,从而选择任意一级的选项。
设置 props.checkStrictly = true 可使节点的选中状态不影响其父节点和子节点,从而可以选择任意一级的选项。
选择任意一级选项(单选)
选择任意一级选项(多选)
<template>
<div class="m-4">
<p>Select any level of options (Single selection)</p>
<el-cascader :options="options" :props="props1" clearable />
</div>
<div class="m-4">
<p>Select any level of options (Multiple selection)</p>
<el-cascader :options="options" :props="props2" clearable />
</div>
</template>
<script lang="ts" setup>
const props1 = {
checkStrictly: true,
}
const props2 = {
multiple: true,
checkStrictly: true,
}
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
动态加载
选中节点时动态加载其子节点。
设置 lazy = true 来开启动态加载,您需要通过 lazyload 来指定如何加载数据源。 lazyload 有两个参数,第一个参数 node 是当前点击的节点,resolve 是一个必须调用的回调函数,表示加载已完成。 为了更准确地显示节点状态,您可以添加 leaf 字段(可通过 props.leaf 修改)来指示它是否为叶子节点。 否则,将通过是否具有子节点来推断。
<template>
<el-cascader :props="props" />
</template>
<script lang="ts" setup>
import type { CascaderProps } from 'element-plus'
let id = 0
const props: CascaderProps = {
lazy: true,
lazyLoad(node, resolve) {
const { level } = node
setTimeout(() => {
const nodes = Array.from({ length: level + 1 }).map((item) => ({
value: ++id,
label: `Option - ${id}`,
leaf: level >= 2,
}))
// Invoke `resolve` callback to return the child nodes data and indicate the loading is finished.
resolve(nodes)
}, 1000)
},
}
</script>
可筛选
使用关键字搜索并选择选项。
在 el-cascader 中添加 filterable 即可开启过滤。 Cascader 会匹配标签或父级标签(根据 show-all-levels)包含输入关键字的节点。 当然,您可以通过 filter-method 自定义搜索逻辑,它接受一个函数,第一个参数是 node,第二个参数是 keyword,需要返回一个布尔值指示是否匹配。
可搜索(单选)
可搜索(多选)
<template>
<div class="m-4">
<p>Filterable (Single selection)</p>
<el-cascader
placeholder="Try searchingL Guide"
:options="options"
filterable
/>
</div>
<div class="m-4">
<p>Filterable (Multiple selection)</p>
<el-cascader
placeholder="Try searchingL Guide"
:options="options"
:props="props"
filterable
/>
</div>
</template>
<script lang="ts" setup>
const props = {
multiple: true,
}
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
自定义节点内容
您可以自定义级联选择器节点的内容。
您可以通过 scoped slot 自定义级联选择器节点的内容。 您可以在作用域中访问 node 和 data,分别代表当前节点的 Node 对象和节点数据。
<template>
<el-cascader :options="options">
<template #default="{ node, data }">
<span>{{ data.label }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</template>
<script lang="ts" setup>
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
自定义搜索建议内容 2.9.5
您可以通过 suggestion-item 插槽自定义过滤建议项。 您可以在作用域中访问 item,代表建议项。
<template>
<el-cascader :options="options" filterable placeholder="Try searching: Guide">
<template #suggestion-item="{ item }">
<span>🔍 {{ item.pathLabels.join(' > ') }}</span>
</template>
</el-cascader>
</template>
<script lang="ts" setup>
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
级联面板
CascaderPanel 是 Cascader 的核心组件,具有单选、多选、动态加载等各种功能。
与 el-cascader 一样,您可以通过 options 设置备选项,并通过 props 开启其他功能,详情请参阅下方的 API 表。
- 指南
- 组件
- 资源
<template>
<el-cascader-panel :options="options" />
</template>
<script lang="ts" setup>
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
{
value: 'color',
label: 'Color',
},
{
value: 'typography',
label: 'Typography',
},
{
value: 'icon',
label: 'Icon',
},
{
value: 'button',
label: 'Button',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
{
value: 'checkbox',
label: 'Checkbox',
},
{
value: 'input',
label: 'Input',
},
{
value: 'input-number',
label: 'InputNumber',
},
{
value: 'select',
label: 'Select',
},
{
value: 'cascader',
label: 'Cascader',
},
{
value: 'switch',
label: 'Switch',
},
{
value: 'slider',
label: 'Slider',
},
{
value: 'time-picker',
label: 'TimePicker',
},
{
value: 'date-picker',
label: 'DatePicker',
},
{
value: 'datetime-picker',
label: 'DateTimePicker',
},
{
value: 'upload',
label: 'Upload',
},
{
value: 'rate',
label: 'Rate',
},
{
value: 'form',
label: 'Form',
},
],
},
{
value: 'data',
label: 'Data',
children: [
{
value: 'table',
label: 'Table',
},
{
value: 'tag',
label: 'Tag',
},
{
value: 'progress',
label: 'Progress',
},
{
value: 'tree',
label: 'Tree',
},
{
value: 'pagination',
label: 'Pagination',
},
{
value: 'badge',
label: 'Badge',
},
],
},
{
value: 'notice',
label: 'Notice',
children: [
{
value: 'alert',
label: 'Alert',
},
{
value: 'loading',
label: 'Loading',
},
{
value: 'message',
label: 'Message',
},
{
value: 'message-box',
label: 'MessageBox',
},
{
value: 'notification',
label: 'Notification',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'menu',
label: 'Menu',
},
{
value: 'tabs',
label: 'Tabs',
},
{
value: 'breadcrumb',
label: 'Breadcrumb',
},
{
value: 'dropdown',
label: 'Dropdown',
},
{
value: 'steps',
label: 'Steps',
},
],
},
{
value: 'others',
label: 'Others',
children: [
{
value: 'dialog',
label: 'Dialog',
},
{
value: 'tooltip',
label: 'Tooltip',
},
{
value: 'popover',
label: 'Popover',
},
{
value: 'card',
label: 'Card',
},
{
value: 'carousel',
label: 'Carousel',
},
{
value: 'collapse',
label: 'Collapse',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
{
value: 'sketch',
label: 'Sketch Templates',
},
{
value: 'docs',
label: 'Design Documentation',
},
],
},
]
</script>
自定义标签 2.10.3
您可以自定义标签。
在 el-cascader 的插槽中插入自定义标签。 collapse-tags、collapse-tags-tooltip、max-collapse-tags 将不再起作用。
使用插槽可以实现更灵活的显示控制。
仅显示顶级标签
<template>
<div class="m-4">
<p>Using slots allows for more flexible control over the display.</p>
<el-cascader :options="options" :props="props" clearable>
<template #tag="{ data }">
<el-tag
v-for="(item, index) in getTags(data)"
:key="item"
:color="index % 2 === 0 ? '#FFDE0A' : ''"
>
{{ item }}
</el-tag>
</template>
</el-cascader>
<p>Display top-level tags only</p>
<el-cascader :options="options" :props="props" clearable>
<template #tag="{ data }">
<el-tag v-for="item in getTopLevelTags(data)" :key="item">
{{ item }}
</el-tag>
</template>
</el-cascader>
</div>
</template>
<script lang="ts" setup>
import type { Tag } from 'element-plus'
const props = { multiple: true }
const options = [
{
value: 1,
label: 'Asia',
children: [
{
value: 2,
label: 'China',
children: [
{ value: 3, label: 'Beijing' },
{ value: 4, label: 'Shanghai' },
{ value: 5, label: 'Hangzhou' },
],
},
{
value: 6,
label: 'Japan',
children: [
{ value: 7, label: 'Tokyo' },
{ value: 8, label: 'Osaka' },
{ value: 9, label: 'Kyoto' },
],
},
{
value: 10,
label: 'Korea',
children: [
{ value: 11, label: 'Seoul' },
{ value: 12, label: 'Busan' },
{ value: 13, label: 'Taegu' },
],
},
],
},
{
value: 14,
label: 'Europe',
children: [
{
value: 15,
label: 'France',
children: [
{ value: 16, label: 'Paris' },
{ value: 17, label: 'Marseille' },
{ value: 18, label: 'Lyon' },
],
},
{
value: 19,
label: 'UK',
children: [
{ value: 20, label: 'London' },
{ value: 21, label: 'Birmingham' },
{ value: 22, label: 'Manchester' },
],
},
],
},
{
value: 23,
label: 'North America',
children: [
{
value: 24,
label: 'US',
children: [
{ value: 25, label: 'New York' },
{ value: 26, label: 'Los Angeles' },
{ value: 27, label: 'Washington' },
],
},
{
value: 28,
label: 'Canada',
children: [
{ value: 29, label: 'Toronto' },
{ value: 30, label: 'Montreal' },
{ value: 31, label: 'Ottawa' },
],
},
],
},
]
const getTags = (data: Tag[]) => {
return data.map((item) => item.text)
}
const getTopLevelTags = (data: Tag[]) => {
const set: Set<string> = new Set()
for (const datum of data) {
let parent = datum.node?.parent
while (parent && parent.level !== 1) {
parent = parent.parent
}
const label = parent?.data?.label
label && set.add(label)
}
return [...set]
}
</script>
选中值显示策略 2.10.5
控制在多选模式下如何显示选中值。
在多选模式下,您可以使用 show-checked-strategy 来控制如何显示选中值。 默认策略是 child,显示所有选中的子节点。 parent 策略则在选中所有子节点时仅显示父节点。
策略:child(默认,显示所有选中的子节点)
策略:parent(当所有子节点都被选中时仅显示父节点)
<template>
<div class="m-4">
<p>Strategy: child (default, show all selected child nodes)</p>
<el-cascader
v-model="value1"
:options="options"
:props="props"
show-checked-strategy="child"
clearable
@change="handleChange1"
/>
</div>
<div class="m-4">
<p>
Strategy: parent (show only parent nodes when all children are selected)
</p>
<el-cascader
v-model="value2"
:options="options"
:props="props"
show-checked-strategy="parent"
clearable
@change="handleChange2"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const value1 = ref([])
const value2 = ref([])
const props = {
multiple: true,
}
const handleChange1 = (value) => {
console.log('Child strategy:', value)
}
const handleChange2 = (value) => {
console.log('Parent strategy:', value)
}
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
],
},
]
</script>
点击节点即选中 2.10.5
仅在使用 multiple 或 checkStrictly 属性时有效。
您可以添加 checkOnClickNode,以便除了点击前缀图标外,还可以点击节点本身进行选中。
使用 showPrefix 切换前缀的可见性。
添加 checkOnClickLeaf 以仅选中叶子节点(最后一个子节点),默认启用。
严格检查 | 单选模式
多选模式
<template>
<div class="flex flex-col items-center">
<el-switch
v-model="showPrefix"
active-text="show prefix"
inactive-text="hide prefix"
/>
<div class="flex flex-wrap">
<div class="m-4">
<p>checkStrictly | Single mode</p>
<el-cascader
v-model="value"
:options="options"
:props="props1"
clearable
/>
</div>
<div class="m-4">
<p>Multiple mode</p>
<el-cascader
v-model="value2"
show-checked-strategy="parent"
:options="options"
:props="props2"
clearable
/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
const value = ref()
const value2 = ref()
const showPrefix = ref(true)
const props1 = computed(() => ({
showPrefix: showPrefix.value,
checkStrictly: true,
checkOnClickNode: true,
}))
const props2 = computed(() => ({
showPrefix: showPrefix.value,
multiple: true,
checkOnClickNode: true,
}))
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
],
},
],
},
{
value: 'component',
label: 'Component',
children: [
{
value: 'basic',
label: 'Basic',
children: [
{
value: 'layout',
label: 'Layout',
},
],
},
{
value: 'form',
label: 'Form',
children: [
{
value: 'radio',
label: 'Radio',
},
],
},
],
},
{
value: 'resource',
label: 'Resource',
children: [
{
value: 'axure',
label: 'Axure Components',
},
],
},
]
</script>
自定义页眉和页脚 2.10.5
您可以使用插槽自定义下拉列表的页眉和页脚。
使用插槽来自定义内容。
自定义页眉内容
自定义页脚内容
<template>
<div class="cascader-custom-header-footer">
<div>
<p>Custom header content</p>
<el-cascader
v-model="value"
popper-class="cascader-custom-header"
:options="options"
:props="props"
clearable
>
<template #header>
<el-checkbox
v-model="checkAll"
:indeterminate="indeterminate"
@change="handleCheckAll"
>
All
</el-checkbox>
</template>
</el-cascader>
</div>
<div>
<p>Custom footer content</p>
<el-cascader v-model="value" :options="options" :props="props" clearable>
<template #footer>
<el-button link size="small" @click="handleClear"> Clear </el-button>
</template>
</el-cascader>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import type { CascaderOption, CheckboxValueType } from 'element-plus'
const props = { multiple: true }
const checkAll = ref(false)
const indeterminate = ref(false)
const value = ref<string[][]>([])
const options = ref([
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{ value: 'consistency', label: 'Consistency' },
{ value: 'feedback', label: 'Feedback' },
{ value: 'efficiency', label: 'Efficiency' },
{ value: 'controllability', label: 'Controllability' },
],
},
],
},
])
const getAllValuePaths = computed(() => {
const result: string[][] = []
const queue: { node: CascaderOption; path: string[] }[] = options.value.map(
(node) => ({ node, path: [node.value] })
)
while (queue.length > 0) {
const { node, path } = queue.shift()!
if (node.children?.length) {
node.children.forEach((child) => {
queue.push({ node: child, path: [...path, child.value as string] })
})
} else {
result.push(path)
}
}
return result
})
watch(value, (val) => {
if (val.length === 0) {
checkAll.value = false
indeterminate.value = false
} else if (val.length === getAllValuePaths.value.length) {
checkAll.value = true
indeterminate.value = false
} else {
indeterminate.value = true
}
})
const handleCheckAll = (val: CheckboxValueType) => {
indeterminate.value = false
value.value = val ? getAllValuePaths.value : []
}
const handleClear = () => {
value.value = []
}
</script>
<style scoped>
.cascader-custom-header-footer {
display: flex;
}
.cascader-custom-header-footer > div {
flex: 1;
text-align: center;
}
.cascader-custom-header-footer > div:not(:last-child) {
border-right: 1px solid var(--el-border-color);
}
.cascader-custom-header .el-checkbox {
display: flex;
height: unset;
}
</style>
虚拟滚动 2.14.0
处理大量数据时,可以开启虚拟滚动以提高性能。
将 virtual-scroll 设置为 true 以开启虚拟滚动。 您还可以通过 height 自定义菜单高度,通过 item-size 自定义节点高度。 默认高度为 204px,默认项目大小为 34px。
<template>
<el-cascader
v-model="value"
:options="options"
:filter-method="filterMethod"
filterable
virtual-scroll
clearable
placeholder="Select with large data"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { CascaderNode } from 'element-plus'
interface CascaderExampleOption {
value: string
label: string
children?: CascaderExampleOption[]
}
const value = ref<string[]>([])
const filterMethod = (node: CascaderNode, keyword: string) => {
return node.text.toLowerCase().includes(keyword.toLowerCase())
}
const generateOptions = (count: number): CascaderExampleOption[] => {
return Array.from({ length: count }).map((_, index) => ({
value: `option-${index}`,
label: `Option ${index + 1}`,
children: [
{
value: `child-${index}-1`,
label: `Child ${index + 1}-1`,
children: [
{
value: `grandchild-${index}-1-1`,
label: `Grandchild ${index + 1}-1-1`,
},
{
value: `grandchild-${index}-1-2`,
label: `Grandchild ${index + 1}-1-2`,
},
],
},
{
value: `child-${index}-2`,
label: `Child ${index + 1}-2`,
},
],
}))
}
const options = ref<CascaderExampleOption[]>(generateOptions(20000))
</script>
自定义搜索建议宽度 2.14.0
默认情况下,建议面板(过滤时)的宽度是根据匹配选项的最大宽度计算的。 如果您通过 suggestion-item 插槽自定义了建议选项,选项中显示的文本很可能不等于 label 的值,从而导致计算错误。 在这种情况下,您可以使用 fit-input-width 属性来固定其宽度。 当值为 number 时,宽度为特定的固定像素值。
提示
fit-input-width 属性仅控制搜索期间建议面板的宽度,不会影响默认的级联面板。
<template>
<div class="flex flex-wrap gap-4 items-center">
<el-cascader
v-model="value"
:options="options"
placeholder="Default expanding panel"
filterable
/>
<el-cascader
v-model="value"
:options="options"
placeholder="Fit input width"
filterable
fit-input-width
/>
<el-cascader
v-model="value"
:options="options"
placeholder="Fixed width (400px)"
filterable
:fit-input-width="400"
>
<template #suggestion-item="{ item }">
<div>{{ item.text }} (Custom content that is very long)</div>
</template>
</el-cascader>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const value = ref()
const options = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
]
</script>
Cascader API
Cascader 属性
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| model-value / v-model | 绑定值 | string / number /array | — |
| options | 可选项的数据源,value 和 label 的键名可以通过 CascaderProps 自定义。 | array | — |
| props | 配置选项,请参阅下方的 CascaderProps 表。 | object | — |
| size | 输入框尺寸 | 枚举 | — |
| 占位符 | 输入框占位文本 | string | — |
| disabled | 级联选择器是否禁用 | boolean | — |
| 可清空 | 是否可以清空已选项 | boolean | — |
| 清除图标 2.11.0 | 自定义清除图标组件 | string / object | CircleClose |
| 显示完整路径 | 输入框中是否显示选中值的完整路径 | boolean | true |
| collapse-tags | 多选模式下是否折叠标签 | boolean | — |
| 折叠标签提示 | 当鼠标悬停于折叠标签的文本时,是否显示所有选中的标签。 要使用此属性,`collapse-tags` 属性必须设定为 true | boolean | false |
| 折叠标签提示的最大高度 2.10.2 | 折叠标签提示的最大高度。 | string / number | — |
| separator | 选项标签分隔符 | string | ' / ' |
| filterable | 是否可搜索选项 | boolean | — |
| filter-method | 自定义搜索逻辑,第一个参数是 node,第二个参数是 keyword,需要返回一个布尔值指示是否匹配。 | Function | — |
| 防抖 | 输入过滤关键字时的去抖延迟,单位为毫秒 | number | 300 |
| 筛选前钩子 | 筛选前的钩子函数,参数为搜索关键词。 若返回 false 或者返回 Promise 且被 reject,则停止筛选 | Function | — |
| popper-class | 级联选择器下拉菜单和标签提示的自定义类名 | string | '' |
| popper-style | 级联选择器下拉菜单和标签提示的自定义样式 | string / object | — |
| teleported | 级联选择器弹窗是否使用 teleport | boolean | true |
| 效应/主题 2.10.5 | tooltip 主题,内置主题:`dark` / `light` | enum / string | light |
| tag-type | 标签类型 | 枚举 | 信息 |
| 标签效应/主题 2.7.8 | 标签效果 | 枚举 | light |
| validate-event | 是否触发表单验证 | boolean | true |
| 最大折叠标签数 2.3.10 | 显示的最大标签数。 必须设置 collapse-tags 为 true 才能使用 | number | 1 |
| empty-values 2.7.0 | 组件的空值,请参阅 config-provider | array | — |
| value-on-clear 2.7.0 | 清空时的返回值,请参阅 config-provider | string / number / boolean / Function | — |
| 持久化 2.7.8 | 当下拉菜单不活动且 persistent 为 false 时,下拉菜单将被销毁 | boolean | true |
| 备用位置 2.8.1 | 文字提示可能出现的位置列表 popper.js | array | — |
| 位置 2.8.1 | 下拉框出现的位置 | 枚举 | 下左 |
| popper-append-to-body 已弃用 | 是否将弹出菜单附加到 body。 如果弹出框定位错误,可以尝试将此属性设置为 false | boolean | true |
| 选中项显示策略 2.10.5 | 多选模式下显示选中节点的策略。 需要整洁时使用 parent。 当每一项都很重要时,使用 child | 枚举 | 子节点 |
| 虚拟滚动 2.14.0 | 是否针对大数据开启虚拟滚动 | boolean | false |
| 适应输入框宽度 2.14.0 | 建议面板的宽度是否与输入框一致,如果值为 number,则宽度固定 | boolean / number | false |
| 项目大小 2.14.0 | 虚拟滚动时的节点高度 (px) | number | 34 |
| 高度 2.14.0 | 虚拟滚动时的菜单高度 (px) | number | 204 |
Cascader 事件
| 名称 | 描述 | 类型 |
|---|---|---|
| change | 当绑定值变化时触发 | Function |
| expand-change | 当展开节点发生变化时触发 | Function |
| blur | 当级联选择器失去焦点时触发 | Function |
| focus | 当级联选择器获得焦点时触发 | Function |
| clear 2.7.7 | 在可清空的 Select 组件上点击清除图标时触发 | Function |
| visible-change | 下拉框出现/隐藏时触发 | Function |
| remove-tag | 多选模式下移除标签时触发 | Function |
Cascader 插槽
| 名称 | 描述 | 类型 |
|---|---|---|
| default | 自定义级联节点的内容,参数分别为当前的 Node 对象和节点数据。 | object |
| empty | 无匹配选项时的内容。 | — |
| 前缀 2.9.4 | 作为输入框前缀的内容 | — |
| 建议项 2.9.5 | 搜索时建议项的自定义内容 | object |
| 标签 2.10.3 | 自定义标签样式 | object |
| 页眉 2.10.5 | 下拉列表顶部的内容 | — |
| 页脚 2.10.5 | 下拉列表底部的内容 | — |
Cascader 暴露的属性和方法
| 名称 | 描述 | 类型 |
|---|---|---|
| getCheckedNodes | 获取当前选中的节点数组,(leafOnly) 是否只返回叶子节点,默认值为 false | Function |
| cascaderPanelRef | 级联面板引用 | object |
| togglePopperVisible 2.2.31 | 切换弹出层的可见状态 | Function |
| contentRef | 级联内容引用 | object |
| presentText 2.8.4 | 已选中的内容文本 | object |
| 获取焦点 2.11.8 | 使输入框元素聚焦 | Function |
| 失去焦点 2.11.8 | 使输入框元素失焦 | Function |
CascaderPanel API
CascaderPanel 属性
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| model-value / v-model | 绑定值 | string/number/array | — |
| options | 可选项的数据源,value 和 label 的键名可以通过 CascaderProps 自定义。 | array | — |
| props | 配置选项,请参阅下方的 CascaderProps 表。 | object | — |
| 虚拟滚动 2.14.0 | 是否针对大数据开启虚拟滚动 | boolean | false |
| 项目大小 2.14.0 | 虚拟滚动时的节点高度 (px) | number | 34 |
| 高度 2.14.0 | 虚拟滚动时的菜单高度 (px) | number | 204 |
CascaderPanel 事件
| 名称 | 描述 | 类型 |
|---|---|---|
| change | 当绑定值变化时触发 | Function |
| 更新绑定的值 | 当绑定值变化时触发 | Function |
| expand-change | 当展开节点发生变化时触发 | Function |
| 关闭 | 关闭面板事件,提供给 Cascader 用于收起面板的判断。 | Function |
CascaderPanel 插槽
| 名称 | 描述 | 类型 |
|---|---|---|
| default | 自定义级联节点的内容,参数分别为当前的 Node 对象和节点数据。 | object |
| 空状态 2.8.3 | 无数据时面板的内容。 | — |
CascaderPanel 暴露的属性和方法
| 名称 | 描述 | 类型 |
|---|---|---|
| getCheckedNodes | 获取当前选中的节点数组,(leafOnly) 是否只返回叶子节点,默认值为 false | Function |
| clearCheckedNodes | 清除选中的节点 | Function |
CascaderProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| 次级菜单的展开方式 | 次级菜单的展开方式触发模式 | 枚举 | click |
| multiple | 是否开启多选 | boolean | false |
| 任意一级选中 | 是否严格遵守父子节点不互相关联,从而可以选择任意一级 | boolean | false |
| 是否返回完整路径 | 在选中节点改变时,是否返回由该节点所有父节点组成的数组,若为 false,则只返回该节点的值 | boolean | true |
| lazy | 是否动态加载子节点,需与 lazyload 属性结合使用 | boolean | false |
| 加载子节点的方法 | 加载子节点数据的方法,仅在 lazy 为 true 时有效。 自版本 2.11.5 起支持 reject 参数。 | Function | — |
| value | 指定节点对象的哪个键用作节点的值 | string | value |
| label | 指定节点对象的哪个键用作节点的标签 | string | label |
| children | 指定节点对象的哪个键用作节点的子节点 | string | children |
| disabled | 指定节点对象的哪个键用作节点的禁用 | string | disabled |
| 叶子节点标识 | 指定哪个键名作为节点的叶子节点标识 | string | 叶子节点标识 |
| 悬停阈值 | 展开选项的悬停阈值 | number | 500 |
| 点击节点即选中 2.10.5 | 是否在点击节点时选中或取消选中该节点 | boolean | false |
| 点击叶子节点即选中 2.10.5 | 是否在点击叶子节点(最后的子节点)时选中或取消选中节点。 | boolean | true |
| 显示前缀 2.10.5 | 是否显示单选或多选框前缀 | boolean | true |
类型声明
显示声明
type CascaderNodeValue = string | number
type CascaderNodePathValue = CascaderNodeValue[]
type CascaderValue =
| CascaderNodeValue
| CascaderNodePathValue
| (CascaderNodeValue | CascaderNodePathValue)[]
type Resolve = (data: any) => void
type ExpandTrigger = 'click' | 'hover'
type LazyLoad = (node: Node, resolve: Resolve, reject: () => void) => void
type isDisabled = (data: CascaderOption, node: Node) => boolean
type isLeaf = (data: CascaderOption, node: Node) => boolean
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 | isDisabled
leaf?: string | isLeaf
hoverThreshold?: number
}
class Node {
readonly uid: number
readonly level: number
readonly value: CascaderNodeValue
readonly label: string
readonly pathNodes: Node[]
readonly pathValues: CascaderNodePathValue
readonly pathLabels: string[]
childrenData: ChildrenData
children: Node[]
text: string
loaded: boolean
/**
* Is it checked
*
* @default false
*/
checked: boolean
/**
* Used to indicate the intermediate state of unchecked and fully checked child nodes
*
* @default false
*/
indeterminate: boolean
/**
* Loading Status
*
* @default false
*/
loading: boolean
// getter
isDisabled: boolean
isLeaf: boolean
valueByOption: CascaderNodeValue | CascaderNodePathValue
// method
appendChild(childData: CascaderOption): Node
calcText(allLevels: boolean, separator: string): string
broadcast(): void
emit(): void
onParentCheck(checked: boolean): void
onChildCheck(): void
setCheckState(checked: boolean): void
doCheck(checked: boolean): void
}
Node as CascaderNode