13 changed files with 494 additions and 144 deletions
@ -0,0 +1,195 @@ |
|||||
|
<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> |
||||
Loading…
Reference in new issue