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

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

相关推荐
WHOVENLY6 小时前
【javaScript】- 笔试题合集(长期更新,建议收藏,目前已更新至31题)
开发语言·前端·javascript
指尖跳动的光6 小时前
将多次提交合并成一次提交
前端·javascript
程序员码歌6 小时前
短思考第263天,每天复盘10分钟,胜过盲目努力一整年
android·前端·后端
oden7 小时前
1 小时速通!手把手教你从零搭建 Astro 博客并上线
前端
若梦plus7 小时前
JS之类型化数组
前端·javascript
若梦plus7 小时前
Canvas 深入解析:从基础到实战
前端·javascript
若梦plus7 小时前
Canvas渲染原理与浏览器图形管线
前端·javascript
C_心欲无痕7 小时前
vue3 - 依赖注入(provide/inject)组件跨层级通信的优雅方案
前端·javascript·vue.js
幺零九零零7 小时前
全栈程序员-前端第二节- vite是什么?
前端