一、组件概述
SelectMultiple.vue 是一个功能强大的移动端多选下拉组件,基于Vue3 Composition API和Vant组件库构建。该组件支持以下核心特性:
- 多种数据格式支持(字符串数组/对象数组)
- 动态字段映射(label/value/disabled)
- 智能搜索过滤 - 禁用状态处理
- 双向数据绑定(支持Array/Object类型)
二、核心功能实现
1. 模板结构解析
<div
:class="[
'qis-form__control',
'qis-form__select'
]"
@click.stop="showPicker = true; selectedValues = value.slice()"
>
<input :value="currentValue" type="hidden" />
<span class="qis-form__select__value">
{{ firstSelected || placeholder }}
</span>
<van-tag type="primary" v-if="currentValue.length > 1">
+{{ currentValue.length - 1 }}
</van-tag>
<i class="iconfont icon-arrow"></i>
</div>
<van-popup
v-model="showPicker"
round
position="bottom"
get-container="#app"
:style="{ height: '50%' }"
>
<van-search
autofocus
placeholder="请输入关键字"
v-model.trim="curVal"
/>
<van-picker
:columns="computedColumns"
:default-index="0"
show-toolbar
:visible-item-count="5"
ref="picker"
@confirm="onConfirm"
@cancel="onCancel"
>
<template slot="option" slot-scope="item">
<div class="custom-picker-item" :class="{ disabled: item[disabledKey] }" @click="toggleItem(item)">
<span
class="checkbox"
:class="{ checked: selectedValues.includes(getValue(item)), disabled: item[disabledKey] }"
></span>
<span class="option-text">{{ getLabel(item) }}</span>
</div>
</template>
</van-picker>
</van-popup>
2. 核心逻辑说明
// 响应式props定义
const props = defineProps({
value: {
type: Array,
required: true,
default: () => []
},
placeholder: {
type: String,
default: '请选择'
},
options: {
type: Array,
required: true,
default: () => []
},
// 新增字段映射配置
labelKey: {
type: String,
default: 'label'
},
valueKey: {
type: String,
default: 'value'
},
// 禁用字段配置
disabledKey: {
type: String,
default: 'disabled'
}
})
const toggleItem = item => {
// 跳过禁用项
if (item[props.disabledKey]) return
const itemValue = getValue(item)
const index = selectedValues.value.findIndex(
v => getValue(v) === itemValue
)
if (index > -1) {
selectedValues.value.splice(index, 1)
} else {
selectedValues.value.push(item)
}
}
三、核心特性解析
1. 数据格式兼容性
// 字符串数组示例
const options1 = ['选项A', '选项B', '选项C']
// 对象数组示例
const options2 = [ { id: 1, name: '选项A', status: 'active' }, { id: 2, name: '选项B', status: 'disabled' } ]
// 使用方式
<SelectMultiple :options="options2" label-key="name" value-key="id" disabled-key="status === 'disabled'" />
2. 智能搜索过滤
// 支持模糊匹配的搜索逻辑
const computedColumns = computed(() => {
const filterVal = curVal.value.trim()
if (!filterVal) return props.options
return props.options.filter(item => {
const label = getLabel(item)
return label.includes(filterVal)
})
})
3. 状态管理
// 双向绑定处理
const currentValue = useVModel(props, 'value', emit)
const onConfirm = () => {
const newValue = selectedValues.value.map(v => getValue(v))
currentValue.value = newValue
showPicker.value = false
}
四、组件使用示例
1. 基础用法
<template>
<SelectMultiple v-model:value="selected" :options="['苹果', '香蕉', '橘子']" />
</template>
2. 对象数组用法
<template>
<SelectMultiple v-model:value="selectedFruits" :options="fruitOptions" label-key="name" value-key="id" disabled-key="isDisabled" />
</template>
<script setup>
const fruitOptions = [
{ id: 1, name: '苹果', isDisabled: false },
{ id: 2, name: '香蕉', isDisabled: true },
{ id: 3, name: '橘子', isDisabled: false }
]
</script>
五、效果展示
六、扩展与优化建议
1. 性能优化
- 对computedColumns添加防抖处理(建议500ms)
- 大数据量时增加虚拟滚动支持
- 添加搜索结果缓存机制
2. 功能增强
- 支持全选/反选操作
- 添加最大选择数量限制
- 支持远程搜索数据加载
- 增加清除选项功能
3. 交互改进
- 添加加载状态指示
- 支持键盘导航操作
- 增加选中计数器显示
- 支持自定义选项渲染插槽
七、注意事项
- 数据格式一致性:确保传入的options与字段映射配置匹配
- 性能考量:超过1000条数据时建议启用虚拟滚动
- 类型处理:避免在value中直接修改对象引用
- 样式隔离:组件样式使用scoped,需确保主题一致性 该组件通过灵活的配置和良好的交互设计,实现了移动端友好的多选下拉体验。通过字段映射和禁用状态支持,可适应各种复杂业务场景,是移动端表单开发的优选组件方案。