在 Vue 项目开发中,经常会遇到复选框组(CheckboxGroup)的互斥需求 ------ 比如包含「无」「不选择」这类选项时,选择该选项需自动取消其他所有选项,选择其他选项则自动取消该互斥选项。为了避免重复开发,我封装了一款通用 Hooks useExclusiveCheckbox,完美适配 Element Plus 和 Ant Design Vue 两大主流 UI 库,本文将详细介绍其使用方法和核心逻辑。
一、Hooks 核心特性
-
🚀 跨 UI 库兼容:无需额外适配,直接支持 Element Plus 和 Ant Design Vue
-
📦 轻量无依赖:仅聚焦互斥逻辑处理,不引入多余依赖
-
🔧 灵活配置:支持自定义互斥选项值(如「无」对应的 value 可设为 '0'、'none' 等)
-
📱 全场景适配:表单提交、筛选条件、系统设置等需要互斥选择的场景均适用
-
✅ 类型安全:基于 TypeScript 开发,提供完整类型提示
二、Hooks 完整代码
TypeScript
/**
* 复选框互斥功能 Hooks
* 适配 Element Plus 和 Ant Design Vue 的 CheckboxGroup 组件
* @param oldValue 上一次选中的值数组(复选框组绑定值)
* @param newValue 当前选中的值数组(复选框组变更后的值)
* @param exclusiveValue 互斥的值(如'none'表示"无"选项)
* @returns 处理后的选中值数组
*/
export const useExclusiveCheckbox = () => {
const handleExclusiveCheckbox = (
oldValue: any[],
newValue: any[],
exclusiveValue: any,
): any[] => {
// 上一次未选择互斥项
if (oldValue && !oldValue.includes(exclusiveValue)) {
if (newValue.includes(exclusiveValue)) {
// 本次选择互斥项:仅保留互斥项(取消其他所有选项)
return [exclusiveValue];
} else {
// 本次未选择互斥项:保持正常多选逻辑
return newValue;
}
}
// 上一次已选择互斥项
else if (oldValue && oldValue.includes(exclusiveValue)) {
if (newValue.length === 0) {
// 本次清空选择:返回空数组
return newValue;
} else {
// 本次选择其他选项:移除互斥项,保留其他选择
const filteredValue = [...newValue];
const index = filteredValue.indexOf(exclusiveValue);
if (index !== -1) {
filteredValue.splice(index, 1);
}
return filteredValue;
}
}
// 第一次选择或异常情况:直接返回新值
else {
return newValue;
}
};
return {
handleExclusiveCheckbox,
};
};
将上述代码保存为 useExclusiveCheckbox.ts 文件,放入项目的 hooks 目录(如 src/hooks/)即可使用。
三、实战使用示例
示例 1:Element Plus CheckboxGroup
Element Plus 的 el-checkbox-group 绑定值为 v-model,change 事件返回新的选中数组,直接调用 Hooks 即可:
TypeScript
<template>
<div class="container">
<h3>Element Plus 互斥复选框示例</h3>
<ElCheckboxGroup
v-model="checkedValues"
@change="handleCheckboxChange"
class="checkbox-group"
>
<ElCheckbox
v-for="item in optionsEnum"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElCheckboxGroup>
<div class="selected-info">当前选中:{{ checkedValues.join(',') || '无' }}</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useExclusiveCheckbox } from '@/hooks/useExclusiveCheckbox';
import { ElCheckboxGroup, ElCheckbox } from 'element-plus';
const { handleExclusiveCheckbox } = useExclusiveCheckbox();
const optionsEnum = [
{
label: "无",
value: "none",
},
{
label: "冠心病",
value: "2",
},
{
label: "糖尿病",
value: "3",
},
{
label: "高血压",
value: "4",
},
{
label: "慢性肾脏病",
value: "5",
},
{
label: "甲状腺疾病",
value: "6",
},
];
// 复选框组绑定值(初始化为空数组)
const checkedValues = ref<any[]>([]);
// 复选框记录旧值
const checkedOldValues = ref<any[]>([]);
// 处理复选框变更事件
const handleCheckboxChange = (newValue: any[]) => {
// 关键:调用互斥处理方法,指定互斥选项为 'none'
const result = handleExclusiveCheckbox(checkedOldValues.value, newValue, 'none');
checkedValues.value = result;
checkedOldValues.value = result;
};
</script>
<style scoped>
.container {
padding: 20px;
}
.checkbox-group {
margin: 10px 0;
}
.selected-info {
margin-top: 15px;
color: #666;
}
</style>
示例 2:Ant Design Vue CheckboxGroup
Ant Design Vue 的 a-checkbox-group 绑定值为 v-model:value,用法与 Element Plus 一致,仅需匹配选项的 value:
TypeScript
<template>
<div class="container">
<h3>Ant Design Vue 互斥复选框示例</h3>
<CheckboxGroup
v-model:value="checkedValues"
@change="handleCheckboxChange"
class="checkbox-group"
>
<Checkbox value="0">无(互斥选项)</Checkbox>
<Checkbox value="1">选项A</Checkbox>
<Checkbox value="2">选项B</Checkbox>
<Checkbox value="3">选项C</Checkbox>
</CheckboxGroup>
<div class="selected-info">当前选中:{{ checkedValues.join(',') || '无' }}</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useExclusiveCheckbox } from '@/hooks/useExclusiveCheckbox';
import { CheckboxGroup, Checkbox } from 'ant-design-vue';
const { handleExclusiveCheckbox } = useExclusiveCheckbox();
// 复选框组绑定值(初始化为空数组)
const checkedValues = ref<any[]>([]);
// 复选框记录旧值
const checkedOldValues = ref<any[]>([]);
// 处理复选框变更事件
const handleCheckboxChange = (newValue: any[]) => {
// 关键:调用互斥处理方法,指定互斥选项为 '0'
const result = handleExclusiveCheckbox(checkedOldValues.value, newValue, '0');
checkedValues.value = result;
checkedOldValues.value = result;
};
</script>
<style scoped>
.container {
padding: 20px;
}
.checkbox-group {
margin: 10px 0;
}
.selected-info {
margin-top: 15px;
color: #666;
}
</style>
常见问题解答
Q1:选择互斥项后,其他选项未自动取消?
表单可能初始化有值,如果初始化checkBoxGroup绑定的表单有值的话,则传递给hooks的旧值也需要初始化赋值,否则会导致,第一次选择互斥选项时失效
总结
useExclusiveCheckbox Hooks 封装了复选框组互斥的通用逻辑,无需编写重复代码,即可快速适配两大主流 UI 库,大幅提升开发效率。无论是简单的筛选组件还是复杂的表单场景,都能满足互斥选择需求,同时保证用户体验的一致性。
如果在使用过程中遇到问题或有功能扩展需求,欢迎在评论区留言交流~