UseElSelect - 选择器
组件介绍
UseElSelect 是基于 Element Plus 的
el-select-v2和el-select进行二次封装的通用选择器组件,旨在简化选择器的使用流程、统一交互逻辑、减少重复开发成本。该组件兼容el-select-v2(虚拟滚动版本)和原生el-select两种底层实现,支持单选 / 多选、自定义字段映射、选中值格式转换等核心能力,仅需通过配置项即可完成绝大部分选择器场景的开发,无需重复编写模板代码,大幅提升中后台系统中选择器的开发效率和可维护性。
核心亮点
- 双版本无缝兼容:同时支持 el-select-v2(虚拟滚动)和原生 el-select,通过 useV2 配置项一键切换,既满足大数据量场景下的性能需求(虚拟滚动),也适配小数据量的常规使用场景。
- 灵活的选中值格式适配:针对多选场景,支持通过 isJoin 配置将选中的数组自动转为逗号分隔的字符串,也可保留原生数组格式,适配不同后端接口的数据格式要求,无需手动处理格式转换。
- 极简的模板开发:无需重复编写 el-option 循环、el-select 基础属性绑定等模板代码,仅需传入数据源 options 和少量配置项,即可完成选择器渲染。
- 自定义字段映射:通过 defaultProps 配置项可灵活定义选项的 label 和 value 字段名,无需修改原始数据源结构,适配不同格式的选项列表。
- 自动类型适配:组件内置值类型自动转换逻辑,根据选项数据源的 value 字段类型,自动处理字符串 / 数字类型的选中值转换,避免类型不匹配导致的选中异常。
解决痛点
- 原生 el-select 重复模板代码过多
- 痛点:每个选择器页面都需编写 el-select、el-option 循环标签,重复绑定 placeholder、style、@change 等属性,多选场景还需额外处理数组 / 字符串转换,开发效率低且易出错。
- 解决方案:组件封装了所有基础模板和事件逻辑,模板中仅需引入
<UseElSelect>并传入 options 等核心配置项,减少 90% 以上的重复模板代码,且配置项可统一维护、复用。
- 多选场景值格式处理逻辑不统一
- 痛点:原生多选选择器返回的是数组格式,但部分后端接口要求逗号分隔的字符串,每个页面需手动编写 join()/split() 转换逻辑,不同开发者实现方式不同,易出现格式错误、逻辑不一致问题。
- 解决方案:组件通过 isJoin 配置项统一处理多选值格式,开启后自动将选中数组转为逗号分隔字符串,关闭则保留数组格式,无需手动编写转换逻辑,格式处理规则全局统一。
- 选项字段名不统一,适配成本高
- 痛点:不同业务场景的选项数据源字段名不一致(如有的是 name/id,有的是 label/value),使用原生 el-select 时需手动映射字段,修改数据源结构或在模板中重复编写 label="item.name" 等代码,适配成本高。
- 解决方案:组件通过 defaultProps 配置项支持自定义 label/value 字段名,例如 defaultProps="{ label: 'name', value: 'id' }" 即可适配 name/id 格式的数据源,无需修改原始数据,适配逻辑统一且灵活。
- 虚拟滚动版本切换成本高
- 痛点:原生 el-select 处理大数据量(万级以上选项)时性能差,需切换到 el-select-v2,但两者模板结构、属性绑定有差异,切换时需大幅修改模板代码,成本高且易引入新问题。
- 解决方案:组件内置 useV2 配置项,一键切换 el-select-v2/el-select 底层实现,模板和配置项无需修改,大数据量场景仅需开启 useV2: true 即可享受虚拟滚动性能优化,切换成本几乎为 0。
- 选中值类型不匹配导致选中异常
- 痛点:原生 el-select 不会自动处理选中值的类型(如选项 value 是数字类型,但传入的 modelValue 是字符串),导致选中状态不生效,每个页面需手动转换类型,易遗漏且排查困难。
- 解决方案:组件内置 valueType 计算属性,自动识别选项 value 字段的类型,对传入的 modelValue 进行自动类型转换(如字符串数字转数字类型),避免因类型不匹配导致的选中异常,无需手动处理类型逻辑。
- 跨页面选择器样式 / 交互不一致
- 痛点:中后台系统多个页面的选择器,因无统一封装,宽度、placeholder、选中事件处理逻辑等不一致,影响用户体验,且后期调整样式 / 交互需逐个页面修改,维护成本高。
- 解决方案:组件内置统一的默认样式(如宽度默认 100%)、默认占位符(请选择)和统一的 change 事件处理逻辑,同时支持通过 width、placeholder 等配置项覆盖默认值,既保证全局样式 / 交互一致性,又满足个性化需求。
使用案例
Types
js
import type { ExtractPropTypes } from 'vue'
import componentProps from './props'
/**
* props类型
*/
export type Props = ExtractPropTypes<typeof componentProps>
/**
* emits接口
*/
export interface Emits {
// 更新value值
(e: 'update:modelValue', value: string | number | (string | number)[]): void
// 更新label值
(e: 'update:label', label: string | string[]): void
}ComponentProps
js
import type { PropType } from 'vue'
import type { DictProps } from '@/types/dict'
/**
* 组件props
*/
export default {
/**
* 双向绑定数据源
*/
modelValue: {
type: [String, Number, Array],
default: ''
},
/**
* 选项数据源
*/
options: {
type: Array as PropType<Record<string, any>[]>,
default: () => []
},
/**
* 是否使用v2版本 默认是
*/
useV2: {
type: Boolean,
default: true
},
/**
* 开启多选时是否将选中的数组转为以逗号分隔的字符串 默认否
*/
isJoin: {
type: Boolean,
default: false
},
/**
* placeholder 默认请选择
*/
placeholder: {
type: String,
default: '请选择'
},
/**
* 宽度,默认100%
*/
width: {
type: String,
default: '100%'
},
/**
* 选项默认配置
*/
defaultProps: {
type: Object as PropType<DictProps>,
default: () => ({ label: 'label', value: 'value' })
}
}Props && Emits
js
const props = defineProps(componentProps)
const emits = defineEmits<Emits>()