feat: Upload 上传组件支持根据扩展名过滤文件 (#980)

 Closes: #796,#581
This commit is contained in:
不如摸鱼去 2025-03-27 21:45:37 +08:00 committed by GitHub
parent d23b2bf2c8
commit 51adb6b8a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 109 additions and 44 deletions

View File

@ -601,6 +601,18 @@ const fileList = ref<UploadFile[]>([])
const action: string = 'https://mockapi.eolink.com/zhTuw2P8c29bc981a741931bdd86eb04dc1e8fd64865cb5/upload' const action: string = 'https://mockapi.eolink.com/zhTuw2P8c29bc981a741931bdd86eb04dc1e8fd64865cb5/upload'
``` ```
## 根据文件拓展名过滤
通过设置 `extension` 可以限制选择文件的格式。以下示例限制只能选择 jpg 和 png 格式的图片:
```html
<wd-upload
v-model:file-list="fileList"
:extension="['.jpg', '.png']"
action="https://mockapi.eolink.com/xxx"
></wd-upload>
```
## Attributes ## Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
@ -637,6 +649,7 @@ const action: string = 'https://mockapi.eolink.com/zhTuw2P8c29bc981a741931bdd86e
| successStatus | 接口响应的成功状态statusCode值 | number | - | 200 | 1.3.4 | | successStatus | 接口响应的成功状态statusCode值 | number | - | 200 | 1.3.4 |
| auto-upload | 是否选择文件后自动上传。为 false 时应手动调用 submit() 方法开始上传 | boolean | - | true | 1.3.8 | | auto-upload | 是否选择文件后自动上传。为 false 时应手动调用 submit() 方法开始上传 | boolean | - | true | 1.3.8 |
| upload-method | 自定义上传方法 | UploadMethod | - | - | 1.3.8 | | upload-method | 自定义上传方法 | UploadMethod | - | - | 1.3.8 |
| extension | 根据文件拓展名过滤(H5支持全部类型过滤,微信小程序支持all和file时过滤,其余平台不支持) | string[] | - | - | $LOWEST_VERSION$ |
## accept 的合法值 ## accept 的合法值
@ -692,3 +705,5 @@ const action: string = 'https://mockapi.eolink.com/zhTuw2P8c29bc981a741931bdd86e
| custom-class | 根节点样式类 | - | | custom-class | 根节点样式类 | - |
| custom-evoke-class | 自定义上传按钮样式类 | - | | custom-evoke-class | 自定义上传按钮样式类 | - |
| custom-preview-class | 自定义预览图片列表样式类 | - | | custom-preview-class | 自定义预览图片列表样式类 | - |

View File

@ -44,36 +44,37 @@ abort()
### 方法 ### 方法
| 方法名 | 说明 | 参数 | 返回值 | | 方法名 | 说明 | 参数 | 返回值 | 最低版本 |
|-------|------|------|--------| |-------|------|------|--------|---------|
| startUpload | 开始上传文件 | file: UploadFileItem, options: UseUploadOptions | UniApp.UploadTask \| void | | startUpload | 开始上传文件 | file: UploadFileItem, options: UseUploadOptions | UniApp.UploadTask \| void | - |
| abort | 中断上传 | task?: UniApp.UploadTask | void | | abort | 中断上传 | task?: UniApp.UploadTask | void | - |
| chooseFile | 选择文件 | options: ChooseFileOption | Promise<ChooseFile[]> | | chooseFile | 选择文件 | options: ChooseFileOption | Promise<ChooseFile[]> | - |
### UseUploadOptions ### UseUploadOptions
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 | 最低版本 |
|-----|------|------|--------| |-----|------|------|--------|---------|
| action | 上传地址 | string | - | | action | 上传地址 | string | - | - |
| header | 请求头 | Record<string, any> | {} | | header | 请求头 | Record<string, any> | {} | - |
| name | 文件对应的 key | string | 'file' | | name | 文件对应的 key | string | 'file' | - |
| formData | 其它表单数据 | Record<string, any> | {} | | formData | 其它表单数据 | Record<string, any> | {} | - |
| fileType | 文件类型 | 'image' \| 'video' \| 'audio' | 'image' | | fileType | 文件类型 | 'image' \| 'video' \| 'audio' | 'image' | - |
| statusCode | 成功状态码 | number | 200 | | statusCode | 成功状态码 | number | 200 | - |
| uploadMethod | 自定义上传方法 | UploadMethod | - | | uploadMethod | 自定义上传方法 | UploadMethod | - | - |
| onSuccess | 上传成功回调 | Function | - | | onSuccess | 上传成功回调 | Function | - | - |
| onError | 上传失败回调 | Function | - | | onError | 上传失败回调 | Function | - | - |
| onProgress | 上传进度回调 | Function | - | | onProgress | 上传进度回调 | Function | - | - |
### ChooseFileOption ### ChooseFileOption
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 | 最低版本 |
|-----|------|------|--------| |-----|------|------|--------|---------|
| multiple | 是否支持多选文件 | boolean | false | | multiple | 是否支持多选文件 | boolean | false | - |
| sizeType | 所选的图片的尺寸 | Array | ['original', 'compressed'] | | sizeType | 所选的图片的尺寸 | Array | ['original', 'compressed'] | - |
| sourceType | 选择文件的来源 | Array | ['album', 'camera'] | | sourceType | 选择文件的来源 | Array | ['album', 'camera'] | - |
| maxCount | 最大可选数量 | number | 9 | | maxCount | 最大可选数量 | number | 9 | - |
| accept | 接受的文件类型 | 'image' \| 'video' \| 'media' \| 'file' \| 'all' | 'image' | | accept | 接受的文件类型 | 'image' \| 'video' \| 'media' \| 'file' \| 'all' | 'image' | - |
| compressed | 是否压缩视频 | boolean | true | | compressed | 是否压缩视频 | boolean | true | - |
| maxDuration | 视频最大时长(秒) | number | 60 | | maxDuration | 视频最大时长(秒) | number | 60 | - |
| camera | 摄像头朝向 | 'back' \| 'front' | 'back' | | camera | 摄像头朝向 | 'back' \| 'front' | 'back' | - |
| extension | 根据文件拓展名过滤(H5支持全部类型过滤,微信小程序支持all和file时过滤,其余平台不支持) | string[] | - |

View File

@ -92,6 +92,23 @@
</template> </template>
</wd-upload> </wd-upload>
</demo-block> </demo-block>
<!-- #ifdef H5 || MP-WEIXIN -->
<demo-block title="根据扩展名过滤">
<!-- #ifdef H5 -->
<wd-upload v-model:file-list="fileList18" :extension="['.jpg', '.png']" :action="action"></wd-upload>
<view style="margin: 10px 0">选择视频时过滤mp4</view>
<wd-upload accept="video" v-model:file-list="fileList19" :extension="['.mp4']" :action="action"></wd-upload>
<view style="margin: 10px 0">上传所有类型文件时过滤.pdf和.docx</view>
<wd-upload accept="all" v-model:file-list="fileList21" :extension="['.pdf', '.docx']" :action="action"></wd-upload>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view style="margin-bottom: 10px">选择文件时过滤.txt文件</view>
<wd-upload accept="file" v-model:file-list="fileList19" :extension="['.txt']" :action="action"></wd-upload>
<view style="margin: 10px 0">选择所有文件时过滤.jpg和.mp4</view>
<wd-upload accept="all" v-model:file-list="fileList20" :extension="['.jpg', '.mp4']" :action="action"></wd-upload>
<!-- #endif -->
</demo-block>
<!-- #endif -->
</page-wraper> </page-wraper>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -136,6 +153,10 @@ const fileList17 = ref<UploadFile[]>([
url: 'https://registry.npmmirror.com/wot-design-uni-assets/*/files/panda.jpg' url: 'https://registry.npmmirror.com/wot-design-uni-assets/*/files/panda.jpg'
} }
]) ])
const fileList18 = ref<UploadFile[]>([])
const fileList19 = ref<UploadFile[]>([])
const fileList20 = ref<UploadFile[]>([])
const fileList21 = ref<UploadFile[]>([])
const upload14 = ref<UploadInstance>() const upload14 = ref<UploadInstance>()

View File

@ -44,6 +44,8 @@ export interface UseUploadOptions {
onProgress?: (res: UniApp.OnProgressUpdateResult, file: UploadFileItem) => void onProgress?: (res: UniApp.OnProgressUpdateResult, file: UploadFileItem) => void
// 是否自动中断之前的上传任务 // 是否自动中断之前的上传任务
abortPrevious?: boolean abortPrevious?: boolean
// 根据文件拓展名过滤(H5支持全部类型过滤,微信小程序支持all和file时过滤,其余平台不支持)
extension?: string[]
} }
export function useUpload(): UseUploadReturn { export function useUpload(): UseUploadReturn {
@ -225,15 +227,19 @@ export function useUpload(): UseUploadReturn {
accept, accept,
compressed, compressed,
maxDuration, maxDuration,
camera camera,
extension
}: ChooseFileOption): Promise<ChooseFile[]> { }: ChooseFileOption): Promise<ChooseFile[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
switch (accept) { switch (accept) {
case 'image': case 'image':
uni.chooseImage({ uni.chooseImage({
count: multiple ? Math.min(maxCount, 9) : 1, count: multiple ? Math.min(maxCount || 9, 9) : 1, // 默认9,最大9
sizeType, sizeType,
sourceType, sourceType,
// #ifdef H5
extension,
// #endif
success: (res) => resolve(formatImage(res)), success: (res) => resolve(formatImage(res)),
fail: reject fail: reject
}) })
@ -244,6 +250,9 @@ export function useUpload(): UseUploadReturn {
compressed, compressed,
maxDuration, maxDuration,
camera, camera,
// #ifdef H5
extension,
// #endif
success: (res) => resolve(formatVideo(res)), success: (res) => resolve(formatVideo(res)),
fail: reject fail: reject
}) })
@ -251,7 +260,7 @@ export function useUpload(): UseUploadReturn {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
case 'media': case 'media':
uni.chooseMedia({ uni.chooseMedia({
count: multiple ? Math.min(maxCount, 9) : 1, count: multiple ? Math.min(maxCount || 9, 9) : 1, // 默认9,最大9
sourceType, sourceType,
sizeType, sizeType,
camera, camera,
@ -262,8 +271,9 @@ export function useUpload(): UseUploadReturn {
break break
case 'file': case 'file':
uni.chooseMessageFile({ uni.chooseMessageFile({
count: multiple ? Math.min(maxCount, 100) : 1, count: multiple ? Math.min(maxCount || 100, 100) : 1, // 默认100,最大100
type: accept, type: accept,
extension,
success: (res) => resolve(res.tempFiles), success: (res) => resolve(res.tempFiles),
fail: reject fail: reject
}) })
@ -272,16 +282,18 @@ export function useUpload(): UseUploadReturn {
case 'all': case 'all':
// #ifdef H5 // #ifdef H5
uni.chooseFile({ uni.chooseFile({
count: multiple ? Math.min(maxCount, 100) : 1, count: multiple ? Math.min(maxCount || 100, 100) : 1, // 默认100,最大100
type: accept, type: accept,
extension,
success: (res) => resolve(res.tempFiles as ChooseFile[]), success: (res) => resolve(res.tempFiles as ChooseFile[]),
fail: reject fail: reject
}) })
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
uni.chooseMessageFile({ uni.chooseMessageFile({
count: multiple ? Math.min(maxCount, 100) : 1, count: multiple ? Math.min(maxCount || 100, 100) : 1, // 默认100,最大100
type: accept, type: accept,
extension,
success: (res) => resolve(res.tempFiles), success: (res) => resolve(res.tempFiles),
fail: reject fail: reject
}) })
@ -291,9 +303,12 @@ export function useUpload(): UseUploadReturn {
default: default:
// 默认选择图片 // 默认选择图片
uni.chooseImage({ uni.chooseImage({
count: multiple ? Math.min(maxCount, 9) : 1, count: multiple ? Math.min(maxCount || 9, 9) : 1, // 默认9,最大9
sizeType, sizeType,
sourceType, sourceType,
// #ifdef H5
extension,
// #endif
success: (res) => resolve(formatImage(res)), success: (res) => resolve(formatImage(res)),
fail: reject fail: reject
}) })

View File

@ -5,27 +5,33 @@ import type { ImageMode } from '../wd-img/types'
export interface ChooseFileOption { export interface ChooseFileOption {
// 是否支持多选文件 // 是否支持多选文件
multiple: boolean multiple?: boolean
// 所选的图片的尺寸 // 所选的图片的尺寸
sizeType?: UploadSizeType[] sizeType?: UploadSizeType[]
// 选择文件的来源 // 选择文件的来源
sourceType: UploadSourceType[] sourceType?: UploadSourceType[]
// 最大允许上传个数 // 最大允许上传个数
maxCount: number maxCount?: number
// 接受文件类型 // 接受文件类型
accept: UploadFileType accept?: UploadFileType
/** /**
* accept video * accept video
*/ */
compressed: boolean compressed?: boolean
/** /**
* accept video | media * accept video | media
*/ */
maxDuration: number maxDuration?: number
/** /**
* 使 accept video | media backfront * 使 accept video | media backfront
*/ */
camera: UploadCameraType camera?: UploadCameraType
/**
* ,H5
* ,
* : ['.jpg'] .jpg文件
*/
extension?: string[]
} }
export type UploadFileItem = { export type UploadFileItem = {
@ -330,7 +336,13 @@ export const uploadProps = {
* UploadMethod * UploadMethod
* - * -
*/ */
uploadMethod: Function as PropType<UploadMethod> uploadMethod: Function as PropType<UploadMethod>,
/**
* ,
* H5支持全部类型过滤
* all和file时过滤,
*/
extension: Array as PropType<string[]>
} }
export type UploadProps = ExtractPropTypes<typeof uploadProps> export type UploadProps = ExtractPropTypes<typeof uploadProps>

View File

@ -409,7 +409,7 @@ function handleProgress(res: UniApp.OnProgressUpdateResult, file: UploadFileItem
* @description 选择文件的实际操作将chooseFile自己用promise包了一层 * @description 选择文件的实际操作将chooseFile自己用promise包了一层
*/ */
function onChooseFile(currentIndex?: number) { function onChooseFile(currentIndex?: number) {
const { multiple, maxSize, accept, sizeType, limit, sourceType, compressed, maxDuration, camera, beforeUpload } = props const { multiple, maxSize, accept, sizeType, limit, sourceType, compressed, maxDuration, camera, beforeUpload, extension } = props
chooseFile({ chooseFile({
multiple, multiple,
@ -419,7 +419,8 @@ function onChooseFile(currentIndex?: number) {
accept, accept,
compressed, compressed,
maxDuration, maxDuration,
camera camera,
extension
}) })
.then((res) => { .then((res) => {
// file // file