本来想从网上找一个封装好的直接用,没找到(可能是我没怎么找吧),然后就自己简单封装了一下,如有不好的地方,希望各位大佬多多指导(欢迎多多评论)
效果图(支持通过关键字搜索)
1.子组件
<template>
<div>
<van-field
:modelValue="selectedItems"
readonly
clearable
required
:label="label"
:name="name"
v-bind="$attrs"
@click="showPopup"
/>
<van-popup
v-model:show="popupVisible"
position="bottom"
class="popup-style"
>
<div>
<div class="pad10 flex-between showMultipleButton">
<van-button plain size="normal" @click="cancelSelection"
>取消</van-button
>
<!-- 标题 -->
<div class="bold">
{
{ label }}
</div>
<van-button
plain
type="primary"
size="normal"
@click="confirmSelection"
>确定</van-button
>
</div>
<van-field
left-icon="search"
v-model.trim="searchKeyword"
clearable
placeholder="请输入搜索关键字"
></van-field>
</div>
<div class="checkbox-style">
<van-checkbox-group v-model="checkedValue">
<van-cell-group>
<van-cell
v-for="(item, index) in filteredColumns"
:key="index"
:title="item.text"
clickable
@click="toggle(index)"
>
<template #right-icon>
<van-checkbox
:name="item.value"
:ref="(el) => (checkboxRefs[index] = el)"
@click.stop
/>
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
</div>
</van-popup>
</div>
</template>
<script setup>
import { onMounted, ref, onBeforeUpdate, computed, nextTick } from "vue";
const props = defineProps({
options: {
type: Array,
required: true,
},
modelValue: {
type: Array,
default: () => [],
},
label: String,
name: String,
});
const emit = defineEmits(["update:modelValue"]);
const selectedItems = ref([]);
const popupVisible = ref(false);
const searchKeyword = ref(null);
const checkboxRefs = ref([]);
const checkedValue = ref([]);
onMounted(() => {
nextTick(() => {
reShow();
});
});
// 异步数据回显方法
const findTextsByValues = (valuesToFind, data) => {
return valuesToFind.map((value) => {
const foundItem = data.find((item) => item.value === value);
return foundItem ? foundItem.text : null;
});
};
const reShow = () => {
if (props.modelValue) {
if (Array.isArray(props.options)) {
selectedItems.value = findTextsByValues(props.modelValue, props.options);
}
}
};
const toggle = (index) => {
checkboxRefs.value[index].toggle();
};
onBeforeUpdate(() => {
checkboxRefs.value = [];
});
// 弹出层
const showPopup = () => {
checkedValue.value = props.modelValue;
popupVisible.value = true;
};
// 取消
const cancelSelection = () => {
popupVisible.value = false;
};
// 确定
const confirmSelection = () => {
selectedItems.value = findTextsByValues(checkedValue.value, props.options);
emit("update:modelValue", checkedValue.value);
popupVisible.value = false;
};
// 弹出层搜索框
const filteredColumns = computed(() => {
return props.options.filter((item) => {
return item.text.includes(searchKeyword.value);
});
});
</script>
<style scoped>
.popup-style {
height: 21.25rem;
}
.showMultipleButton {
padding-bottom: 0;
}
.showMultipleButton .van-button {
border: 0;
}
.flex-between {
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.bold {
font-weight: bold;
color: #444;
}
.checkbox-style {
height: 220px;
overflow-y: auto;
}
</style>
2.父组件
<template>
<VanMultipleSelect
:options="dataList"
v-model="form.selectedValue"
label="城市"
:name="form.selectedValue"
placeholder="请选择城市"
error-message-align="right"
input-align="right"
:rules="[{ required: true, message: '请选择城市' }]"
></VanMultipleSelect>
</template>
<script setup lang="ts">
import VanMultipleSelect from "./components/VanMultipleSelect.vue";
import { ref } from "vue";
const dataList = ref([
{ text: "杭州", value: "Hangzhou" },
{ text: "宁波", value: "Ningbo" },
{ text: "温州", value: "Wenzhou" },
{ text: "绍兴", value: "Shaoxing" },
{ text: "湖州", value: "Huzhou" },
]);
const form = ref({
selectedValue: [],
});
</script>