1. 前言
接手得 uniapp 开发的微信小程序项目,新的开发需求是需要同时上传图片和视频,但是之前的上传都没有进行封装,都是每个页面需要的时候单独实现,现在新的需求,有多个地方都需要上传图片、视频或语音等,这样就需要封装一个组件,然后发现部分地方使用了 uni-file-picker 组件,但是 uni-file-picker 在 grid 的时候只能进行图片的展示,如果是 video 或者 all 的时候,就会直接列表展示的文件名列表,不满足我当前的需求,因此在 uni-file-picker 基础上进行再次适配当前需求的封装。
2. 实现效果
3. 分析
- 图片和视频同时预览展示,就需要判断上传的是否是视频或者图片;
- 根据接口判断是否上传文件的格式是否在允许范围内;
- 使用 uni-file-picker 需要改造,将文件预览列表隐藏,使用自定义的预览文件。
4. 判断是图片
export const isImageFile = (filename) => {
// 定义常见的图片文件扩展名
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
// 获取文件扩展名
const fileExtension = filename.split('.').pop().toLowerCase()
// 判断文件扩展名是否在图片扩展名列表中
return imageExtensions.includes(fileExtension)
}
5. 判断是视频
// 判断是不是视频
export const isVideoFile = (filename) => {
// 定义常见的视频文件扩展名
const videoExtensions = [
'mp4',
'avi',
'mov',
'mkv',
'flv',
'wmv',
'webm',
'mpeg',
'mpg'
]
// 获取文件扩展名
const fileExtension = filename.split('.').pop().toLowerCase()
// 判断文件扩展名是否在视频扩展名列表中
return videoExtensions.includes(fileExtension)
}
6. 根据接口判断是否是可上传格式文件
export const canUploadFile = (filename) => {
const extensions = ['bmp','gif','jpg','jpe','png','mp4','mp3']
// 获取文件扩展名
const fileExtension = filename.split('.').pop().toLowerCase()
// 判断文件扩展名是否在视频扩展名列表中
return extensions.includes(fileExtension)
}
7. 预览图片和视频
uploadPreview 插槽是方便自定义预览,这里我是用 tailwindcss 实现了一个默认的视频和图片的预览样式。
<slot name="uploadPreview">
<view class="cc mr-[20rpx] wh-[160] bd-[8] flex-none relative" v-for="(item,index) in fileLists" :key="item.url">
<view class="icon-del-box" @click.stop="deletePic(item)">
<view class="icon-del"></view>
<view class="icon-del rotate"></view>
</view>
<image v-if="item.isImage" :src="item.url" class="wh-[160] bd-[8] flex-none"></image>
<video v-else-if="item.isVideo" :src="item.url" class="wh-[160] bd-[8] flex-none"></video>
</view>
</slot>
8. 使用 uni-file-picker 上传
- 注意:是对 list 模式的文件上传,所以直接将 mode 的值写死 list;
- uploadButtom 自定义上传样式。
<uni-file-picker
:limit="limit"
:file-mediatype="fileMediatype"
@select="getUpload"
:is-upload-file="false"
:autoUpload="false"
mode="list"
:value="fileLists"
>
<slot name="uploadButtom">
<view
class="cc bg-[#F9F9F9] wh-[160] bd-[8] b-[2rpx_#D0D0D0_dashed] flex-none"
>
<image :src="$icon.publishAddIcon" class="wh-[48]"></image>
</view>
</slot>
</uni-file-picker>
9. 完整组件实现
<template>
<view class="ac">
<slot name="uploadPreview">
<view class="cc mr-[20rpx] wh-[160] bd-[8] flex-none relative" v-for="(item,index) in fileLists" :key="item.url">
<view class="icon-del-box" @click.stop="deletePic(item)">
<view class="icon-del"></view>
<view class="icon-del rotate"></view>
</view>
<image v-if="item.isImage" :src="item.url" class="wh-[160] bd-[8