实现思路
利用 slot-scope
功能自定义节点内容,我们在 template
内加入一个具有 exceeded-overlay
类的遮罩元素,并为其定义一个点击事件来提示超出最大限制。当选中数量未达到最大限制时,遮罩元素将保持隐藏;若超过限制,则显示。但这样做有一个问题:在达到最大限制后,点击已选中的节点仍会弹出“超出最大限制”的错误提示。
为解决此问题,我们需要隐藏已选中节点的遮罩元素。巧妙运用 CSS 技巧,我们能够实现这一需求,确保在各种场景下都能正常使用。
代码片段
代码实现
<template>
<el-cascader
v-model="selectedLocations"
:options="locationOptions"
popper-class="location"
placeholder="期望工作地区"
filterable
:props="cascaderProps"
:show-all-levels="false"
>
<template slot-scope="{ data }">
{
{ data.label }}
<span
v-if="selectedLocations.length >= 2"
class="exceeded-overlay"
@click="handleSelectionExceeded"
></span>
</template>
</el-cascader>
</template>
<script>
export default {
data() {
return {
cascaderProps: {
multiple: true,
expandTrigger: 'hover',
checkStrictly: true
},
selectedLocations: [],
locationOptions: [
{
value: 1002, label: "北京" },
{
value: 1024, label: "上海" },
{
value: 1001,
label: "安徽",
children: [
{
value: 100106, label: "合肥" },
{
value: 100114, label: "芜湖" },
{
value: 100101, label: "蚌埠" }
]
},
{
value: 1003,
label: "福建",
children: [
{
value: 100300, label: "福州" },
{
value: 100307, label: "厦门" },
{
value: 100306, label: "三明" },
{
value: 100305, label: "泉州" },
{
value: 100301, label: "龙岩" }
]
}
]
}
},
methods: {
handleSelectionExceeded() {
this.$message.error('最多只能选择2个')
}
}
}
</script>
<style lang="scss">
.location {
/* 遮罩元素-覆盖整个li元素 */
.exceeded-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
z-index: 20;
}
/* 选中节点隐藏遮罩元素 */
.el-checkbox.is-checked ~ .el-cascader-node__label {
.exceeded-overlay {
display: none;
}
}
}
</style>
watch 的实现方案
实际上,通过使用 watch
来监听选中值也是可行的。当选中数量超过最大限制时,我们可以将选中值恢复到原始状态。这种方法简洁明了,逻辑清晰且易于理解。但是,它带来了一个副作用:一旦超过最大限制,级联选择器会自动跳回至 options
数组的第一个位置,并且脱离用户当前选中的位置。我并不喜欢这样的体验。
这种方式会打扰用户当前操作,体验上似乎不是很友好
<template>
<el-cascader
v-model="selectedLocations"
popper-class="location"
placeholder="期望工作地区"
filterable
:props="{ multiple: true, expandTrigger: 'hover', checkStrictly: true }"
:show-all-levels="false"
:options="locationOptions"
@change="handleLocationChange"
>
</el-cascader>
</template>
<script>
export default {
data() {
return {
selectedLocations: [], // 保存用户选择的地区信息
locationOptions: [ // 包含所有可选的地区数据对象
{
value: 1002, label: "北京" },
{
value: 1024, label: "上海" },
{
value: 1001,
label: "安徽",
children: [
{
value: 100106, label: "合肥" },
{
value: 100114, label: "芜湖" },
{
value: 100101, label: "蚌埠" }
]
},
{
value: 1003,
label: "福建",
children: [
{
value: 100300, label: "福州" },
{
value: 100307, label: "厦门" },
{
value: 100306, label: "三明" },
{
value: 100305, label: "泉州" },
{
value: 100301, label: "龙岩" }
]
}
]
}
},
watch: {
// 期望工作地区,最多允许选择2个
selectedLocations: function (val, oldVal) {
if (val.length > 2) {
this.$message.error('最多可选2个')
this.$nextTick(() => (this.selectedLocations = oldVal))
}
}
}
}
</script>