vue3 element下拉全选反选加搜索

<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();
};

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值