由于vant移动端组件中,没有提供select组件。下面我封装一个支持可模糊搜素,远程搜素select选择器
效果如下:
Select Attributes
1.封装组件(vanFieldSelectPicker)
<template>
<van-popup teleport="body" v-model:show="state.showPicker" position="bottom">
<div class="van-picker__toolbar">
<button type="button" class="van-picker__cancel" @click="state.showPicker = false">取消</button>
<div class="van-ellipsis van-picker__title">{{ $attrs.title }}</div>
<button type="button" class="van-picker__confirm" @click="confirmClick">确认</button>
</div>
<div class="van-field-box">
<van-field
v-if="props.isSearch"
v-model="state.searchVal"
input-align="left"
:placeholder="$attrs.placeholder || '搜索'"
@update:model-value="inputChange"
/>
<van-loading size="30px" vertical v-if="loading">加载中...</van-loading>
<van-empty image="search" v-if="state.columns.length == 0 && !loading" description="" />
<van-cell-group v-else>
<van-cell
:class="{ selected: item[options.value] == state.selectItem.value }"
v-for="(item, index) in state.columns"
:key="item[options.value]"
:title="item[options.label]"
clickable
@click="cellClick(item)"
>
<template #right-icon>
<van-icon style="display: flex !important;justify-content: center;align-items: center;" v-if="item[options.value] == state.selectItem.value" name="success" />
</template>
</van-cell>
</van-cell-group>
</div>
</van-popup>
</template>
<script setup>
import { reactive, watch, computed } from "vue";
import { debounce } from "lodash-es";
const emit = defineEmits(["cellClick", "remoteMethed", "confirm", "update:modelValue", "update:show"]);
//props
const props = defineProps({
columns: Array,
remote: Boolean,
loading: Boolean,
modelValue: String,
show: Boolean,
options: {
type: Object,
default: () => {
return { label: "label", value: "value" };
},
},
//是否支持搜索
isSearch: {
type: Boolean,
default: false,
},
});
//data响应式数据
const state = reactive({
selectItem: {}, //选中的选项
showPicker: false,
searchVal: "", //输入框value值
columns: [], //数据
});
//确认点击
const confirmClick = () => {
emit("update:show", false);
emit("confirm", state.selectItem);
};
//选项的点击
const cellClick = (item) => {
//已经选中的,再次点击不处理
// if (item.value == props.selectItem.value) return;
state.selectItem = item;
emit("cellClick", item);
};
//防抖处理 模糊搜索value值改变触发
const inputChange = debounce(() => {
//获取远程数据
if (props.remote) {
emit("remoteMethed", state.searchVal);
return;
}
//获取所有的选项
if (!state.searchVal) {
state.columns = props.columns;
} else {
state.columns = props.columns.filter((item) => item[props.options.label].indexOf(state.searchVal) > -1);
}
},500);
//展示/隐藏处理
state.showPicker = computed({
set(showPicker) {
emit("update:show", showPicker);
},
get() {
return props.show;
},
});
//选项数据
watch(
() => props.columns,
(newVal) => {
state.columns = newVal;
},
{ immediate: true }
);
watch(
() => props.modelValue,
(newVal) => {
state.selectItem[props.options.value] = newVal;
},
{ immediate: true }
);
watch(
() => state.showPicker,
(newVal) => {
//隐藏选择框是,清空搜素栏value值
//1.如果是可搜素的 清空选项
//2.如果不是可搜素的,把传过来的选项数据,赋值给当前组件选项数据中
if (!newVal) {
state.searchVal = "";
props.remote && (state.columns = []);
} else {
!props.remote && (state.columns = props.columns);
}
}
);
</script>
<style lang="scss" scoped>
.van-field-box {
height: 264px;
overflow-y: auto;
padding-bottom: 20px;
}
::v-deep(.van-cell) {
&.selected {
background: #f5f7fa;
color: #1989fa;
}
}
</style>
注意:需要你安装一下lodash-es (因为远程搜索我加了一个防抖处理)
npm install lodash-es
2.父组件使用
<template>
<div class="sel-picker">
<van-field v-model="state.selectItem.label" is-link readonly label="城市" placeholder="选择城市" @click="fieldClick" />
<van-field-select-picker
v-model="state.selectItem.value"
v-model:show="state.show"
placeholder="请选择"
:columns="state.columns"
:options="{ label: 'label', value: 'value' }"
isSearch
@confirm="confirm"
></van-field-select-picker>
</div>
</template>
<script setup lang="ts">
import vanFieldSelectPicker from "@/components/vanFieldSelectPicker.vue";
import { reactive } from "vue";
let state = reactive({
show: false,
selectItem: { label: "", value: "" },
columns: [
{ label: "北京", value: "beijing" },
{ label: "上海", value: "shanghai" },
{ label: "深圳", value: "shenzhen" },
{ label: "广州", value: "guangzhou" },
{ label: "杭州", value: "hangzhou" },
{ label: "重庆", value: "chongqing" },
],
});
const fieldClick = () => {
state.show = true;
};
const confirm = (item) => {
console.log(item);
state.selectItem = item;
};
</script>
<style scoped lang="scss"></style>
下一章封装vue3.x vant 移动端多选的select效果