第一步:封装
<!-- media-uploader.vue -->
<template>
<view class="up-page">
<!-- 图片展示 -->
<view class="show-box" v-for="(item,index) in imageList" :key="'img-'+index">
<image class="full" :src="item" @tap="previewImage(item)" />
<view class="delect-icon" @tap="handleDelete('image', index)" v-if="!disabled">
<image class="full" :src="clearIcon" />
</view>
</view>
<!-- 视频展示 -->
<view class="show-box" v-for="(item, index) in videoList" :key="'video-'+index">
<video class="full" :src="item" />
<view class="delect-icon" @tap="handleDelete('video', index)" v-if="!disabled">
<image class="full" :src="clearIcon" />
</view>
</view>
<!-- 上传按钮 -->
<view v-if="showUploadBtn&&!disabled" @tap="showMediaPicker" class="box-mode upload-btn">
<image class="full" :src="selectfile" />
</view>
</view>
</template>
<script>
const DEFAULT_CONFIG = {
maxCount: 9,
sourceTypes: ['拍摄', '相册', '拍摄或相册'],
cameraOptions: [{
value: 'back',
name: '后置摄像头',
checked: true
},
{
value: 'front',
name: '前置摄像头'
}
]
}
export default {
name: 'MediaUploader',
props: {
// 配置项
maxCount: {
type: Number,
default: DEFAULT_CONFIG.maxCount
},
// 初始媒体文件
initialImages: {
type: Array,
default: () => []
},
initialVideos: {
type: Array,
default: () => []
},
// 是否禁用状态
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
clearIcon: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCAwaDE2YTQgNCAwIDAgMSA0IDR2MTZINGE0IDQgMCAwIDEtNC00VjB6IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXIpIiBmaWxsLW9wYWNpdHk9Ii45OCIgZmlsdGVyPSJ1cmwoI2ZpbHRlcjBfYikiLz48cGF0aCBkPSJNMTAuOTQgOS45OTlsMi44NjMtMi44NTdhLjY2OS42NjkgMCAxIDAtLjk0Ni0uOTQ2TDEwIDkuMDYgNy4xNDMgNi4xOTZhLjY2OS42NjkgMCAwIDAtLjk0Ni45NDZsMi44NjQgMi44NTctMi44NjQgMi44NTdhLjY2Ni42NjYgMCAwIDAgLjIxNyAxLjA5Mi42NjQuNjY0IDAgMCAwIC43MjktLjE0NkwxMCAxMC45MzhsMi44NTcgMi44NjRhLjY2Ny42NjcgMCAwIDAgMS4wOTItLjIxNy42NjYuNjY2IDAgMCAwLS4xNDYtLjcyOUwxMC45MzkgMTB6IiBmaWxsPSIjZmZmIi8+PGRlZnM+PGZpbHRlciBpZD0iZmlsdGVyMF9iIiB4PSItNCIgeT0iLTQiIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlR2F1c3NpYW5CbHVyIGluPSJCYWNrZ3JvdW5kSW1hZ2UiIHN0ZERldmlhdGlvbj0iMiIvPjxmZUNvbXBvc2l0ZSBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0iaW4iIHJlc3VsdD0iZWZmZWN0MV9iYWNrZ3JvdW5kQmx1ciIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9ImVmZmVjdDFfYmFja2dyb3VuZEJsdXIiIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXIiIHgxPSIyMCIgeDI9IjE1LjU4NiIgeTI9IjIyLjk0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agc3RvcC1jb2xvcj0iIzBEMUUyOCIgc3RvcC1vcGFjaXR5PSIuOCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzA1MEUxMiIgc3RvcC1vcGFjaXR5PSIuNjUiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4=',
selectfile: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIuMjUiIHk9Ii4yNSIgd2lkdGg9IjYzLjUiIGhlaWdodD0iNjMuNSIgcng9IjMuNzUiIGZpbGw9IiNGMkYyRjIiIHN0cm9rZT0iI0YyRjJGMiIgc3Ryb2tlLXdpZHRoPSIuNSIvPjxyZWN0IHg9IjE2IiB5PSIzMSIgd2lkdGg9IjMyIiBoZWlnaHQ9IjIiIHJ4PSIxIiBmaWxsPSIjQkZCRkJGIi8+PHJlY3QgeD0iMzMiIHk9IjE2IiB3aWR0aD0iMzIiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKDkwIDMzIDE2KSIgZmlsbD0iI0JGQkZCRiIvPjwvc3ZnPg==',
imageList: [...this.initialImages],
videoList: [...this.initialVideos],
sourceTypeIndex: 2,
cameraIndex: 0,
action: this.$config.apiUrl+'/sys/common/upload',
}
},
computed: {
showUploadBtn() {
return (this.imageList.length + this.videoList.length) < this.maxCount
}
},
methods: {
// 统一媒体选择
showMediaPicker() {
uni.showActionSheet({
title: '选择上传类型',
itemList: ['图片', '视频'],
success: ({
tapIndex
}) => {
tapIndex === 0 ? this.chooseImage() : this.chooseVideo()
}
})
},
// 选择图片
async chooseImage() {
try {
const token = uni.getStorageSync('Access-Token');
const res = await uni.chooseImage({
count: this.remainingCount,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera']
})
res[1].tempFiles.map(item=>{
uni.uploadFile({
url: this.action,
fileType: 'image',
file: item,
name: 'file',
header: {
"X-Access-Token":token
},
formData: {
'biz': 'temp'
},
success: (file) =>{
this.imageList.push(this.$config.apiUrl+'/sys/common/static/'+JSON.parse(file.data).message);
this.$emit('update:images', this.imageList)
},
fail: (err)=>{}
})
})
} catch (error) {
this.$emit('error', error)
}
},
// 选择视频
async chooseVideo() {
try {
const token = uni.getStorageSync('Access-Token');
const res = await uni.chooseVideo({
maxDuration: 15,
camera: DEFAULT_CONFIG.cameraOptions[this.cameraIndex].value,
sourceType: ['album', 'camera']
})
uni.uploadFile({
url: this.action,
fileType: 'video',
file: res.tempFile,
name: 'file',
header: {
"X-Access-Token":token
},
formData: {
'biz': 'temp'
},
success: (file) =>{
this.videoList.push(this.$config.apiUrl+'/sys/common/static/'+JSON.parse(file.data).message);
this.$emit('update:videos', this.videoList)
},
fail: (err)=>{}
})
} catch (error) {
this.$emit('error', error)
}
},
// 统一删除处理
async handleDelete(type, index) {
try {
await this.confirmDelete(type)
if (type === 'image') {
this.imageList.splice(index, 1)
this.$emit('update:images', this.imageList)
} else {
this.videoList.splice(index, 1)
this.$emit('update:videos', this.videoList)
}
this.$emit('delete', {
type,
index
})
} catch (error) {
/* 取消删除不处理 */
}
},
// 确认删除弹窗
confirmDelete(type) {
return new Promise((resolve, reject) => {
uni.showModal({
title: '提示',
content: `是否要删除该${type === 'image' ? '图片' : '视频'}`,
success: ({
confirm
}) => confirm ? resolve() : reject()
})
})
},
// 图片预览
previewImage(current) {
uni.previewImage({
current,
urls: this.imageList
})
}
}
}
</script>
<style lang="scss" scoped>
.box-mode {
width: 27vw;
height: 27vw;
border-radius: 8rpx;
overflow: hidden;
}
.full {
width: 100%;
height: 100%;
}
.up-page {
display: flex;
flex-wrap: wrap;
display: flex;
width: 100%;
padding: 0 15px 12px;
.show-box:nth-child(3n) {
margin-right: 0;
}
.show-box {
position: relative;
margin-bottom: 4vw;
margin-right: 4vw;
@extend .box-mode;
.delect-icon {
height: 40rpx;
width: 40rpx;
position: absolute;
right: 0rpx;
top: 0rpx;
z-index: 1;
}
}
}
</style>
第二步:使用
<media-uploader :max-count="5" :initial-images.sync="localImages1" :initial-videos.sync="localVideos1" @update:images="updateImages1" @update:videos="updateVideos1" :disabled="false"/>