2026-04-07 16:02:19 +08:00

139 lines
2.9 KiB
Vue

<template>
<div class="base-picker">
<!-- 使用 van-field 作为展示区域 -->
<van-field
:modelValue="displayValue"
:label="label"
:placeholder="placeholder"
:disabled="disabled"
:readonly="true"
:right-icon="rightIcon"
:clickable="!disabled"
@click="openPicker"
/>
<!-- 弹出层选择器 -->
<van-popup v-model:show="showPicker" position="bottom" round>
<van-picker
:columns="columns"
:title="pickerTitle"
:loading="loading"
show-toolbar
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { Field, Popup, Picker } from 'vant'
// Props 定义
const props = defineProps({
// 双向绑定值 (v-model)
modelValue: {
type: [String, Number],
default: null
},
// 选项数据,默认格式 [{ label: '显示名', value: '值' }]
options: {
type: Array,
required: true,
default: () => []
},
// 左侧标签文字
label: {
type: String,
default: ''
},
// 占位符
placeholder: {
type: String,
default: '请选择'
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// Picker 顶部标题
pickerTitle: {
type: String,
default: '请选择'
},
// 加载状态
loading: {
type: Boolean,
default: false
},
// 右侧图标(可自定义)
rightIcon: {
type: String,
default: 'arrow-down'
},
// 自定义选项的 label 字段名
labelKey: {
type: String,
default: 'label'
},
// 自定义选项的 value 字段名
valueKey: {
type: String,
default: 'value'
}
})
// Emits 定义
const emit = defineEmits(['update:modelValue', 'change'])
// 控制弹出层显示
const showPicker = ref(false)
// 处理 Picker 数据格式:将 options 转为 Picker 需要的文本数组
const columns = computed(() => {
return props.options.map(item => {
return {
text: item[props.labelKey],
value: item[props.valueKey]
}
})
})
// 根据选中的值,获取显示文本
const displayValue = computed(() => {
if (props.modelValue === null || props.modelValue === undefined || props.modelValue === '') {
return ''
}
const selected = props.options.find(item => item[props.valueKey] === props.modelValue)
return selected ? selected[props.labelKey] : ''
})
// 打开选择器
const openPicker = () => {
if (!props.disabled) {
showPicker.value = true
}
}
// 确认选择
const onConfirm = ({ selectedValues, selectedOptions }) => {
const value = selectedOptions[0][props.valueKey]
const label = selectedOptions[0][props.labelKey]
emit('update:modelValue', value)
emit('change', { value, label })
showPicker.value = false
}
</script>
<style scoped>
.base-picker {
width: 100%;
}
/* 可选:调整 Field 的只读样式 */
:deep(.van-field__control--readonly) {
cursor: pointer;
}
</style>