You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
4.8 KiB
195 lines
4.8 KiB
<template>
|
|
<view class="single-picker">
|
|
<fui-picker
|
|
:layer="1"
|
|
:options="formattedOptions"
|
|
:show="show"
|
|
@change="onChange"
|
|
@cancel="onCancel"
|
|
:title="title"
|
|
></fui-picker>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
/**
|
|
* 通用单选选择器组件
|
|
* @description 基于FirstUI的fui-picker组件封装的通用单选选择器,支持灵活配置
|
|
*/
|
|
export default {
|
|
name: "single-picker",
|
|
props: {
|
|
/**
|
|
* 是否显示选择器
|
|
* @property {Boolean} show - 控制选择器的显示与隐藏
|
|
* @default false
|
|
*/
|
|
show: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
/**
|
|
* 数据源
|
|
* @property {Array} data - 选择器数据数组
|
|
* @default []
|
|
*/
|
|
data: {
|
|
type: Array,
|
|
default() {
|
|
return []
|
|
},
|
|
validator(value) {
|
|
// 允许空数组或非空数组
|
|
return Array.isArray(value)
|
|
}
|
|
},
|
|
/**
|
|
* 值字段名
|
|
* @property {String} valueKey - 用作选项值的字段名
|
|
* @default 'value'
|
|
*/
|
|
valueKey: {
|
|
type: String,
|
|
default: 'value'
|
|
},
|
|
/**
|
|
* 文本字段名
|
|
* @property {String|Array} textKey - 用作显示文本的字段名,支持字符串或数组
|
|
* @default 'text'
|
|
*/
|
|
textKey: {
|
|
type: [String, Array],
|
|
default: 'text'
|
|
},
|
|
/**
|
|
* 文本分隔符
|
|
* @property {String} textSeparator - 当textKey为数组时,各字段之间的分隔符
|
|
* @default '-'
|
|
*/
|
|
textSeparator: {
|
|
type: String,
|
|
default: '-'
|
|
},
|
|
/**
|
|
* 选择器标题
|
|
* @property {String} title - 选择器顶部显示的标题
|
|
* @default '请选择'
|
|
*/
|
|
title: {
|
|
type: String,
|
|
default: '请选择'
|
|
},
|
|
/**
|
|
* 默认占位文本
|
|
* @property {String} placeholder - 当字段为空时显示的占位文本
|
|
* @default '未命名'
|
|
*/
|
|
placeholder: {
|
|
type: String,
|
|
default: '未命名'
|
|
}
|
|
},
|
|
computed: {
|
|
/**
|
|
* 格式化后的选项数据,适配fui-picker组件
|
|
*/
|
|
formattedOptions() {
|
|
// 确保data是数组且不为空
|
|
if (!this.data || !Array.isArray(this.data) || this.data.length === 0) {
|
|
return []
|
|
}
|
|
|
|
return this.data.map(item => {
|
|
return this.getDisplayText(item)
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
/**
|
|
* 获取显示文本
|
|
* @param {Object} item - 数据项
|
|
* @returns {String} 显示文本
|
|
*/
|
|
getDisplayText(item) {
|
|
if (!item || typeof item !== 'object') {
|
|
return this.placeholder
|
|
}
|
|
|
|
if (Array.isArray(this.textKey)) {
|
|
// 如果textKey是数组,组合多个字段
|
|
const textParts = this.textKey.map(key => {
|
|
return item[key] || this.placeholder
|
|
})
|
|
return textParts.join(this.textSeparator)
|
|
} else {
|
|
// 如果textKey是字符串,直接取对应字段
|
|
return item[this.textKey] || this.placeholder
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 获取选项值
|
|
* @param {Object} item - 数据项
|
|
* @returns {*} 选项值
|
|
*/
|
|
getDisplayValue(item) {
|
|
if (!item || typeof item !== 'object') {
|
|
return null
|
|
}
|
|
return item[this.valueKey]
|
|
},
|
|
|
|
/**
|
|
* 选择器确认事件处理
|
|
* @param {Object} e - 选择器返回的数据对象
|
|
* @emits update:show - 更新show属性
|
|
* @emits change - 选择完成事件
|
|
*/
|
|
onChange(e) {
|
|
// 隐藏选择器
|
|
this.$emit('update:show', false)
|
|
|
|
// 获取选中的索引
|
|
const index = e.index && e.index[0]
|
|
|
|
// 如果没有选中任何项或没有数据,返回
|
|
if (index === undefined || !this.data || !Array.isArray(this.data) || this.data.length === 0 || index >= this.data.length) {
|
|
return
|
|
}
|
|
|
|
// 获取选中的数据项
|
|
const selectedItem = this.data[index]
|
|
|
|
// 如果选中的项不存在,返回
|
|
if (!selectedItem) {
|
|
return
|
|
}
|
|
|
|
// 将选择结果传递给父组件
|
|
this.$emit('change', {
|
|
text: this.getDisplayText(selectedItem),
|
|
value: this.getDisplayValue(selectedItem),
|
|
index: index,
|
|
item: selectedItem
|
|
})
|
|
},
|
|
/**
|
|
* 选择器取消事件处理
|
|
* @emits update:show - 更新show属性
|
|
* @emits cancel - 取消选择事件
|
|
*/
|
|
onCancel() {
|
|
// 隐藏选择器
|
|
this.$emit('update:show', false)
|
|
// 通知父组件取消选择
|
|
this.$emit('cancel')
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.single-picker {
|
|
/* 可以根据需要添加自定义样式 */
|
|
}
|
|
</style>
|