<template>
<!-- 蒙层 -->
<view v-if="visible" class="zy-horizontal-picker-mask-layer" @click="handleMaskClick">
<view :class="{ 'zy-horizontal-picker-mask-false': !mask, 'zy-horizontal-picker-mask': mask }" />
</view>
<!-- 弹窗 -->
<view v-if="visible" class="zy-horizontal-picker-popup-wrapper">
<view class="zy-horizontal-picker-container">
<!-- 横向滚动区域 -->
<scroll-view class="zy-horizontal-picker-scroll" scroll-x enable-flex :show-scrollbar="false">
<view class="zy-horizontal-picker-items" :style="{ '--item-width': itemWidth + 'px' }">
<view
v-for="(item, index) in options"
:key="item.value"
class="zy-horizontal-picker-item"
@click="handleItemClick(item)"
>
<!-- 图标区域 -->
<view class="zy-horizontal-picker-icon-wrapper">
<image
v-if="getIconUrl(item)"
class="zy-horizontal-picker-icon"
:src="getIconUrl(item)"
mode="aspectFit"
/>
<text v-else class="zy-horizontal-picker-icon-placeholder">?</text>
</view>
<!-- 文字区域 -->
<text class="zy-horizontal-picker-label">{{ item.label }}</text>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import { MediaSelector } from '@/utils/mediaSelector'
export default {
name: 'ZyHorizontalPicker',
props: {
// 控制显隐
modelValue: { type: Boolean, default: false },
// 选项列表
options: {
type: Array,
required: false,
default: [
{
value: 'cameraImage',
label: '拍照',
options: { count: 1, sourceType: ['camera'] }
},
{
value: 'mobileImage',
label: '相册',
options: { mediaType: ['image'], count: 9, sourceType: ['album'] }
},
{
value: 'messageImage',
label: '聊天图片',
options: { type: 'image', count: 9 }
},
{
value: 'messageFile',
label: '聊天文件',
options: { type: 'file', count: 9 }
},
{
value: 'cameraVideo',
label: '拍视频',
options: {
sourceType: ['camera'],
compressed: true,
maxDuration: 60,
camera: 'back'
}
},
{
value: 'mobileVideo',
label: '本地视频',
options: { mediaType: ['video'], count: 9, sourceType: ['album'] }
},
{
value: 'messageVideo',
label: '聊天视频',
options: { type: 'video', count: 9 }
}
]
},
// 是否启用蒙层
mask: { type: Boolean, default: true },
// 每个项的宽度(px)
itemWidth: { type: Number, default: 100 }
},
emits: ['update:modelValue', 'change', 'confirm'],
computed: {
visible() {
return this.modelValue
}
},
methods: {
/**
* 获取图标 URL
*/
getIconUrl(item) {
const iconMap = {
mobileImage: '../../static/img/mediaImg/mobileImage.png',
mobileVideo: '../../static/img/mediaImg/mobileVideo.png',
cameraImage: '../../static/img/mediaImg/cameraImage.png',
cameraVideo: '../../static/img/mediaImg/cameraVideo.png',
messageImage: '../../static/img/mediaImg/messageImage.png',
messageVideo: '../../static/img/mediaImg/messageVideo.png',
messageFile: '../../static/img/mediaImg/messageFile.png'
}
return iconMap[item.value] || undefined
},
/**
* 点击某一项
*/
async handleItemClick(item) {
console.log('🚀 ~ handleItemClick ~ item:', item)
try {
const result = await MediaSelector.select(item.value, item.options)
if (result.success || result.partial) {
console.log('成功文件:', result.data.successList)
if (result.partial) {
uni.showToast({ title: `部分失败(${result.failCount})`, icon: 'none' })
}
} else {
// 全部失败 or 用户取消
if (result.data.failCount === 0) {
console.log('用户取消', result)
} else {
console.log('用户取消', result)
}
}
} catch (err) {
console.error('异常:', err)
}
},
/**
* 点击蒙层关闭
*/
handleMaskClick() {
this.close(true)
},
/**
* 关闭弹窗
* @param {Boolean} fromCancel 是否是取消操作触发
*/
close(fromCancel) {
this.$emit('update:modelValue', false)
}
}
}
</script>
<style lang="scss">
/* 蒙层 */
.zy-horizontal-picker-mask-layer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 998;
pointer-events: auto;
}
.zy-horizontal-picker-mask {
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.5;
}
.zy-horizontal-picker-mask-false {
opacity: 0;
}
/* 弹窗外层 */
.zy-horizontal-picker-popup-wrapper {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
z-index: 999;
background-color: #fff;
padding: 20px 0;
padding-bottom: calc(env(safe-area-inset-bottom) + 20px);
border-radius: 16px 16px 0 0;
overflow: hidden;
}
/* 容器 */
.zy-horizontal-picker-container {
display: flex;
justify-content: center;
padding: 20px 0;
}
/* 滚动视图 */
.zy-horizontal-picker-scroll {
white-space: nowrap;
width: 100%;
box-sizing: border-box;
}
/* 项目容器(flex 自适应) */
.zy-horizontal-picker-items {
display: flex;
flex-direction: row;
align-items: center;
height: 120px;
}
/* 单个选项 */
.zy-horizontal-picker-item {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: var(--item-width); /* 支持动态设置宽度 */
margin: 0 16px;
}
/* 图标容器 */
.zy-horizontal-picker-icon-wrapper {
width: 54px;
height: 54px;
border-radius: 50%;
overflow: hidden;
margin-bottom: 12px;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
}
/* 图标 */
.zy-horizontal-picker-icon {
width: 100%;
height: 100%;
}
/* 占位图标 */
.zy-horizontal-picker-icon-placeholder {
font-size: $uni-font-size-16;
color: #999;
}
/* 文字 */
.zy-horizontal-picker-label {
font-size: $uni-font-size-14;
color: $uni-text-color;
text-align: center;
}
</style>
图片和下边的文字中间间距8px
最新发布