el-select下拉框实现复选框多选、全选?

背景:

版本:
vue: '3.3.4'
element-plus: '2.3.7'

el-select的基础多选功能的下拉框需要替换成el-checkbox复选框;

尝试实现代码如下:

<template>
  <el-select v-model="data" multiple popper-class="select-popover-class">
    <el-checkbox :value="selectAll" @change="selectAllHandle"
      >全选</el-checkbox
    >
    <el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label">
      <el-checkbox :value="item.checked" :label="item.label" />
    </el-option>
  </el-select>
</template>

<script setup>
  import { ref, computed } from 'vue';

  const data = ref([]);
  const options = ref([
    { label: '选项1', value: 1, checked: false },
    { label: '选项2', value: 2, checked: true },
    { label: '选项3', value: 3, checked: false },
  ]);
  const flag = ref(true);

  const selectAll = computed(() => {
    const selectMap = options.value.map(item => item.checked);
    return selectMap.length === options.value.length
  });

  const selectAllHandle = (bool) => {
    options.value.forEach((item) => {
      item.checked = bool;
    });
  };
</script>

<style scoped>
  /* 自定义样式 */
  .select-popover-class .el-checkbox {
    padding: 5px 20px;
  }
</style>

样式实现了,但是逻辑上还有如下问题:

  1. 全选功能未能关联单项;
  2. 选择单个选框时,下拉框关闭了。

尝试2

<template>
  <el-select v-model="data" multiple popper-class="select-popover-class">
    <el-checkbox :value="selectAll" @change="selectAllHandle"
      >全选</el-checkbox
    >
    <el-checkbox-group v-model="data" @change="changeHandle">
      <el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label">
      <el-checkbox  :label="item.label" />
    </el-option>
    </el-checkbox-group>
    
  </el-select>
</template>

<script setup>
  import { ref, computed } from 'vue';

  const data = ref(['选项1','选项2']);
  const options = ref([
    { label: '选项1', value: 1 },
    { label: '选项2', value: 2},
    { label: '选项3', value: 3 },
  ]);
  const flag = ref(true);

  const selectAllHandle = (bool) => {
    data.value = bool ? options.value.map(item => item.label) : [];
  };

  const changeHandle = (val) => {
    console.log(val,'val');
  }
</script>

<style scoped>
  /* 自定义样式 */
  .select-popover-class .el-checkbox {
    padding: 5px 20px;
  }
</style>

全选关联单项已实现,但是还有单项选不中,点击单选选择下拉框关闭的问题

阅读 1k
avatarAI BotBETA
### 解决方案

要实现 `el-select` 下拉框中的复选框多选和全选功能,并且解决您遇到的问题,您可以采取以下步骤:

1. **移除 `el-checkbox` 在 `el-option` 中的使用**:
   `el-select` 的 `el-option` 组件不支持直接嵌套 `el-checkbox`。您需要通过逻辑来管理选中状态。

2. **使用 `el-select` 的 `multiple` 和 `collapse-tags` 属性**:
   `multiple` 允许多选,`collapse-tags` 可以让选中的标签折叠显示,以便更好地在下拉框中展示。

3. **全选功能逻辑**:
   全选功能需要正确地同步 `options` 数组中的 `checked` 属性和 `data` 数组中的选中项。

4. **阻止下拉框关闭**:
   可以通过监听 `@visible-change` 事件,在点击 `el-checkbox` 时阻止下拉框关闭。

下面是修改后的代码示例:

<template>
<el-select

v-model="data"
multiple
collapse-tags
popper-class="select-popover-class"
@visible-change="handleVisibleChange"
placeholder="请选择"
<el-option
  v-for="item in options"
  :key="item.value"
  :label="item.label"
  :value="item.value"
>
  <span @click.stop="toggleOption(item)">
    <el-checkbox
      v-model="item.checked"
      :indeterminate="isIndeterminate(item)"
      size="mini"
      @change="handleCheckboxChange(item)"
    />
    {{ item.label }}
  </span>
</el-option>
<el-option>
  <span @click.stop="selectAllOrNone">
    <el-checkbox
      v-model="selectAll"
      size="mini"
      @change="selectAllHandle"
    >
      全选
    </el-checkbox>
  </span>
</el-option>

</el-select>
</template>

<script setup>
import { ref, computed } from 'vue';

const data = ref([]);
const options = ref([
{ label: '选项1', value: 1, checked: false },
{ label: '选项2', value: 2, checked: true },
{ label: '选项3', value: 3, checked: false },
]);
let isVisible = ref(false);

const selectAll = computed(() => {
return options.value.every(item => item.checked);
});

const isIndeterminate = item => {
return !selectAll.value && data.value.includes(item.value);
};

const selectAllHandle = (bool) => {
options.value.forEach(item => {

item.checked = bool;
if (bool) {
  if (!data.value.includes(item.value)) {
    data.value.push(item.value);
  }
} else {
  const index = data.value.indexOf(item.value);
  if (index > -1) {
    data.value.splice(index, 1);
  }
}

});
};

const toggleOption = item => {
item.checked = !item.checked;
if (item.checked && !data.value.includes(item.value)) {

data.value.push(item.value);

} else if (!item.checked) {

const index = data.value.indexOf(item.value);
if (index > -1) {
  data.value.splice(index, 1);
}

}
};

const handleCheckboxChange = item => {
toggleOption(item);
};

const selectAllOrNone = () => {
selectAllHandle(!selectAll.value);
};

const handleVisibleChange = (val) => {
isVisible.value = val;
};

// 在点击 checkbox 时阻止下拉框关闭(如果下拉框已经打开)
watch(() => isVisible.value, (newVal) => {
if (newVal && document.querySelector('.el-select-dropdown__item .el-checkbox')) {

document.querySelector('.el-select-dropdown__item .el-checkbox').addEventListener('click', (e) => {
  e.stopPropagation();
}, { once: true });

}
});
</script>

<style scoped>
.select-popover-class .el-checkbox {
margin-right: 8px;
}
</style>


### 解释

- **`el-checkbox` 在 `el-option` 中**:
  我们通过在 `el-option` 的 `label` 插槽中放置 `el-checkbox`,并使用 `@click.stop` 阻止事件冒泡,防止点击复选框时下拉框关闭。

- **全选逻辑**:
  `selectAllHandle` 函数现在不仅更新 `options` 中的 `checked` 状态,还同步更新 `data` 数组,确保选中项正确。

- **阻止下拉框关闭**:
  使用 `@visible-change` 监听下拉框的显示状态,并在下拉框打开时添加一次性的点击事件监听器,防止点击复选框时下拉框关闭。

这样修改后,您的 `el-select` 下拉框应该能够正确地实现复选框多选、全选功能,并且点击复选框时不会关闭下拉框。
2 个回答
✓ 已被采纳

修复单项选择

单项选择的问题是由于 el-checkbox 嵌套在 el-option 内部。可以直接使用 el-checkbox,而不嵌套在 el-option 内。

防止选择时下拉框关闭

为了防止选择项目时下拉框关闭,可以在复选框上使用 @click.stop 指令,阻止点击事件传播并关闭下拉框。
以下是更新后的代码:

<template>
  <el-select v-model="data" multiple popper-class="select-popover-class" @visible-change="handleVisibleChange">
    <el-checkbox :indeterminate="isIndeterminate" v-model="selectAll" @change="selectAllHandle">全选</el-checkbox>
    <el-checkbox-group v-model="data" @change="changeHandle">
      <el-checkbox v-for="item in options" :key="item.value" :label="item.label" @click.stop>{{ item.label }}</el-checkbox>
    </el-checkbox-group>
  </el-select>
</template>

<script setup>
import { ref, computed } from 'vue';

const data = ref(['选项1', '选项2']);
const options = ref([
  { label: '选项1', value: 1 },
  { label: '选项2', value: 2 },
  { label: '选项3', value: 3 },
]);
const selectAll = ref(false);

const isIndeterminate = computed(() => {
  return data.value.length > 0 && data.value.length < options.value.length;
});

const selectAllHandle = (bool) => {
  data.value = bool ? options.value.map(item => item.label) : [];
};

const changeHandle = (val) => {
  selectAll.value = val.length === options.value.length;
  console.log(val, 'val');
};

const handleVisibleChange = (visible) => {
  if (!visible) {
    // 处理下拉框关闭时的额外逻辑
  }
};
</script>

<style scoped>
/* 自定义样式 */
.select-popover-class .el-checkbox {
  padding: 5px 20px;
}
</style>

关键更改

  1. 直接在 el-select 中使用复选框

    • el-checkbox 直接放置在 el-select 中,而不嵌套在 el-option 内部,从而简化了结构。
  2. 阻止事件传播

    • 使用 @click.stop 指令,防止点击事件传播,避免下拉框在选择项目时关闭。
  3. 不确定状态

    • 添加了 isIndeterminate 计算属性,以处理“全选”复选框的不确定状态。
推荐问题
宣传栏