<template>
<el-select
v-model="selectData"
multiple
:filterable="false"
:placeholder="placeholder"
@clear="clearData"
v-bind="$attrs"
@visible-change="handleChangeVisible"
@remove-tag="handleChange"
>
<div class="sf-select-input">
<el-input v-model="filterValue" placeholder="关键词"></el-input>
</div>
<div class="sf-select-dropdown">
<li class="el-select-dropdown__item sf-no-mark">
<el-checkbox v-model="checkedAll" @change="selectAll">全选</el-checkbox>
<span class="reverse" @click.stop="handleReverseAll">反选</span>
</li>
</div>
<div class="sf-select-dropdown">
<el-scrollbar wrap-class="scrollbar-wrapper" style="width: calc(100% - 10px)">
<el-option v-for="(item, index) in optionList" :key="index" :value="item.value">
<el-checkbox :label="item[props.label]" size="large" @change="changeCheckBox(item, index)" :checked="isChecked(item, index)" v-model="checkBoxObj[index]" />
</el-option>
<el-option hidden label="" value=""></el-option>
</el-scrollbar>
</div>
</el-select>
</template>
<script setup name="FilterSelectMultiple">
import { reactive, ref, watch, toRefs, defineExpose } from "vue";
const props = defineProps({
list: { type: Array, required: true },
id: { type: String, required: true },
label: { type: String, required: true },
modelValue: { type: Array },
placeholder: { type: String, default: "请选择" }
});
const state = reactive({
filterValue: "",
optionList: []
});
const { filterValue, optionList } = toRefs(state);
const emit = defineEmits(["update:modelValue"]);
const checkedAll = ref("false");
const menus = ref([]);
const selectData = ref([]);
const checkBoxObj = ref({});
state.optionList.forEach((res, index) => {
checkBoxObj.value[index] = false;
});
watch(
() => props.list,
() => {
state.optionList = props.list;
}
);
watch(
filterValue,
newVal => {
if (newVal) {
state.optionList = state.optionList.filter(item => item.label.includes(newVal));
} else {
state.optionList = props.list;
}
},
{ immediate: true }
);
const selectAll = value => {
menus.value = [];
selectData.value = [];
if (value) {
state.optionList.forEach((item, index) => {
menus.value.push(item[props.id]);
selectData.value.push(item[props.label]);
checkBoxObj.value[index] = true;
});
} else {
menus.value = [];
selectData.value = [];
state.optionList.forEach((item, index) => {
checkBoxObj.value[index] = false;
});
}
emit("update:modelValue", menus.value);
};
const isChecked = item => {
return menus.value.indexOf(item[props.id]) > -1;
};
const changeCheckBox = item => {
let i = menus.value.indexOf(item[props.id]);
if (i == -1) {
menus.value.push(item[props.id]);
selectData.value.push(item[props.label]);
} else {
menus.value.splice(i, 1);
selectData.value.splice(i, 1);
}
if (menus.value.length == state.optionList.length) {
checkedAll.value = true;
} else {
checkedAll.value = false;
}
emit("update:modelValue", menus.value);
};
const handleChange = val => {
state.optionList.forEach((item, index) => {
if (item[props.id] == val) {
menus.value.splice(item[val], 1);
selectData.value = menus.value;
checkBoxObj.value[index] = false;
}
});
emit("update:modelValue", menus.value);
};
const clearData = () => {
menus.value = [];
selectData.value = [];
emit("update:modelValue", menus.value);
checkedAll.value = false;
state.optionList.forEach((item, index) => {
checkBoxObj.value[index] = false;
});
};
const handleChangeVisible = () => {
state.filterValue = "";
state.optionList = props.list;
};
const handleReverseAll = () => {
menus.value = [];
selectData.value = [];
if (checkedAll.value) {
clearData();
} else {
state.optionList.forEach((item, index) => {
if (checkBoxObj.value[index] == false) {
menus.value.push(item[props.id]);
selectData.value.push(item[props.label]);
checkBoxObj.value[index] = true;
} else {
checkBoxObj.value[index] = false;
}
});
}
emit("update:modelValue", menus.value);
};
defineExpose({ clearData });
</script>
<style lang="scss" scoped>
.sf-select-input {
padding: 5px 8px 5px 5px;
}
.sf-no-mark {
list-style: none;
}
.reverse {
margin-left: 50px;
font-weight: normal;
color: #606266 !important;
}
:deep(.scrollbar-wrapper) {
max-height: 168px !important;
}
:deep(.el-select__tags) {
overflow: hidden;
}
:deep(.el-checkbox.el-checkbox--large) {
display: block;
}
</style>
子组件
父组件
<FilterSelectMultiple
ref="filterSelectMultipleRef"
v-model="searchParam.organizationName"
collapse-tags
collapse-tags-tooltip
clearable
:list="selectList"
id="value"
label="label"
></FilterSelectMultiple>
const filterSelectMultipleRef = ref();
const handleReset = () => {
filterSelectMultipleRef.value.clearData();
reset();
};