Vue 通用复选框组互斥 Hooks:兼容 Element Plus + Ant Design Vue

在 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 库,大幅提升开发效率。无论是简单的筛选组件还是复杂的表单场景,都能满足互斥选择需求,同时保证用户体验的一致性。

如果在使用过程中遇到问题或有功能扩展需求,欢迎在评论区留言交流~

相关推荐
Cache技术分享36 分钟前
258. Java 集合 - 深入探究 NavigableMap:新增方法助力高效数据处理
前端·后端
Jingyou38 分钟前
JavaScript 实现深拷贝
前端·javascript
凡人程序员38 分钟前
搭建 monorepo 项目
前端·javascript
linda261839 分钟前
说说 Map 和 Set 的区别及实际应用
前端·javascript
_一两风39 分钟前
“点一下就能改”——这个功能为首富赚到了多少money?
前端·javascript
小飞侠在吗41 分钟前
vue setup与OptionsAPI
前端·javascript·vue.js
疯不皮41 分钟前
tiptiap3如何实现编辑器内部嵌套多个富文本编辑器
前端·vue.js·开源
溪饱鱼43 分钟前
主动与被动AI交互范式
前端·后端·aigc
我叫黑大帅43 分钟前
如何实现UniApp登录拦截?
前端·javascript·vue.js