From 833064adbd4385cff0dc7a6064921586510f1073 Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 22 May 2021 20:30:09 +0800 Subject: [PATCH] feat(Uploader): max-size prop can be a function (#8744) * feat(Uploader): max-size prop can be a function * chore: revert demo * test: fix snapshot * docs: upd --- src/uploader/README.md | 28 +++++++++++++++++++++++++--- src/uploader/README.zh-CN.md | 24 +++++++++++++++++++++++- src/uploader/Uploader.tsx | 3 ++- src/uploader/test/index.spec.ts | 31 +++++++++++++++++++++++++++++-- src/uploader/utils.ts | 20 +++++++++++++++----- 5 files changed, 94 insertions(+), 12 deletions(-) diff --git a/src/uploader/README.md b/src/uploader/README.md index 8e85f90f0..44c4b6a06 100644 --- a/src/uploader/README.md +++ b/src/uploader/README.md @@ -146,6 +146,28 @@ export default { }; ``` +If you need to make different size limits for different types of files, you can pass a function to the `max-size` props. + +```html + +``` + +```js +import { Toast } from 'vant'; + +export default { + setup() { + const isOverSize = (file) => { + const maxSize = file.type === 'image/jpeg' ? 500 * 1024 : 1000 * 1024; + return file.size >= maxSize; + }; + return { + isOverSize, + }; + }, +}; +``` + ### Custom Upload Area ```html @@ -274,7 +296,7 @@ export default { | name | Input name | _number \| string_ | - | | preview-size | Size of preview image | _number \| string_ | `80px` | | preview-image | Whether to show image preview | _boolean_ | `true` | -| preview-full-image | Whethe to show full screen image preview when image is clicked | _boolean_ | `true` | +| preview-full-image | Whether to show full screen image preview when image is clicked | _boolean_ | `true` | | preview-options | Options of full screen image preview,see [ImagePreview](#/en-US/image-preview) | _object_ | - | | multiple | Whether to enable multiple selection pictures | _boolean_ | `false` | | disabled | Whether to disabled the upload | _boolean_ | `false` | @@ -285,7 +307,7 @@ export default { | after-read | Hook after reading the file | _Function_ | - | | before-read | Hook before reading the file, return false to stop reading the file, can return Promise | _Function_ | - | | before-delete | Hook before delete the file, return false to stop reading the file, can return Promise | _Function_ | - | -| max-size | Max size of file | _number \| string_ | - | +| max-size `v3.0.17` | Max size of file | _number \| string \| (file: File) => boolean_ | - | | max-count | Max count of image | _number \| string_ | - | | result-type | Type of file read result, can be set to `file` `text` | _string_ | `dataUrl` | | upload-text | Upload text | _string_ | - | @@ -308,7 +330,7 @@ export default { | default | Custom icon | - | | preview-cover | Custom content that covers the image preview | `item: FileListItem` | -### Parematers of before-read、after-read、before-delete +### Parameters of before-read、after-read、before-delete | Attribute | Description | Type | | --------- | ------------------------------------ | -------- | diff --git a/src/uploader/README.zh-CN.md b/src/uploader/README.zh-CN.md index bd905ed02..f48554fdc 100644 --- a/src/uploader/README.zh-CN.md +++ b/src/uploader/README.zh-CN.md @@ -159,6 +159,28 @@ export default { }; ``` +如果需要针对不同类型的文件来作出不同的大小限制,可以在 `max-size` 属性中传入一个函数,在函数中通过 `file.type` 区分文件类型,返回 `true` 表示超出限制,`false` 表示未超出限制。 + +```html + +``` + +```js +import { Toast } from 'vant'; + +export default { + setup() { + const isOverSize = (file) => { + const maxSize = file.type === 'image/jpeg' ? 500 * 1024 : 1000 * 1024; + return file.size >= maxSize; + }; + return { + isOverSize, + }; + }, +}; +``` + ### 自定义上传样式 通过默认插槽可以自定义上传区域的样式。 @@ -306,7 +328,7 @@ export default { | after-read | 文件读取完成后的回调函数 | _Function_ | - | | before-read | 文件读取前的回调函数,返回 `false` 可终止文件读取,
支持返回 `Promise` | _Function_ | - | | before-delete | 文件删除前的回调函数,返回 `false` 可终止文件读取,
支持返回 `Promise` | _Function_ | - | -| max-size | 文件大小限制,单位为 `byte` | _number \| string_ | - | +| max-size `v3.0.17` | 文件大小限制,单位为 `byte` | _number \| string \| (file: File) => boolean_ | - | | max-count | 文件上传数量限制 | _number \| string_ | - | | result-type | 文件读取结果类型,可选值为 `file` `text` | _string_ | `dataUrl` | | upload-text | 上传区域文字提示 | _string_ | - | diff --git a/src/uploader/Uploader.tsx b/src/uploader/Uploader.tsx index 3736d4946..de6e3eea9 100644 --- a/src/uploader/Uploader.tsx +++ b/src/uploader/Uploader.tsx @@ -17,6 +17,7 @@ import { filterFiles, isImageFile, readFileContent, + UploaderMaxSize, UploaderResultType, UploaderFileListItem, } from './utils'; @@ -83,7 +84,7 @@ export default defineComponent({ default: () => [], }, maxSize: { - type: [Number, String], + type: [Number, String, Function] as PropType, default: Number.MAX_VALUE, }, maxCount: { diff --git a/src/uploader/test/index.spec.ts b/src/uploader/test/index.spec.ts index bf14b0db1..7ef1f42d6 100644 --- a/src/uploader/test/index.spec.ts +++ b/src/uploader/test/index.spec.ts @@ -3,7 +3,9 @@ import Uploader, { UploaderFileListItem } from '..'; import { mount, later, triggerDrag } from '../../../test'; const mockFileDataUrl = 'data:image/test'; -const mockFile = new File([new ArrayBuffer(10000)], 'test.jpg'); +const mockFile = new File([new ArrayBuffer(10000)], 'test.jpg', { + type: 'test', +}); const IMAGE = 'https://img.yzcdn.cn/vant/cat.jpeg'; const PDF = 'https://img.yzcdn.cn/vant/test.pdf'; @@ -218,7 +220,7 @@ test('before read return promise and reject', async () => { expect(input.element.value).toEqual(''); }); -test('file size overlimit', async () => { +test('should trigger oversize event when file size is overlimit', async () => { const wrapper = mount(Uploader, { props: { maxSize: 1, @@ -250,6 +252,31 @@ test('file size overlimit', async () => { expect(wrapper.emitted<[File]>('oversize')![2]).toBeFalsy(); }); +test('should allow to custom max-size for different type of files', async () => { + const wrapper = mount(Uploader, { + props: { + maxSize(file: File) { + if (file.type === 'test') { + return file.size > 500; + } + return false; + }, + }, + }); + + const input = wrapper.find('.van-uploader__input'); + const fileList = [mockFile]; + + Object.defineProperty(input.element, 'files', { + get: () => jest.fn().mockReturnValue(fileList)(), + }); + + await input.trigger('change'); + + await later(); + expect(wrapper.emitted<[File]>('oversize')![0]).toBeTruthy(); +}); + test('render upload-text', () => { const uploadText = 'Text'; const wrapper = mount(Uploader, { diff --git a/src/uploader/utils.ts b/src/uploader/utils.ts index 661f95586..bda0f2114 100644 --- a/src/uploader/utils.ts +++ b/src/uploader/utils.ts @@ -1,4 +1,4 @@ -import { createNamespace } from '../utils'; +import { createNamespace, isFunction } from '../utils'; import type { ImageFit } from '../image'; import type { Interceptor } from '../utils/interceptor'; @@ -21,6 +21,8 @@ export type UploaderFileListItem = { beforeDelete?: Interceptor; }; +export type UploaderMaxSize = number | string | ((file: File) => boolean); + export function toArray(item: T | T[]): T[] { if (Array.isArray(item)) { return item; @@ -52,20 +54,28 @@ export function readFileContent(file: File, resultType: UploaderResultType) { export function isOversize( items: UploaderFileListItem | UploaderFileListItem[], - maxSize: number | string + maxSize: UploaderMaxSize ): boolean { - return toArray(items).some((item) => item.file && item.file.size > maxSize); + return toArray(items).some((item) => { + if (item.file) { + if (isFunction(maxSize)) { + return maxSize(item.file); + } + return item.file.size > maxSize; + } + return false; + }); } export function filterFiles( items: UploaderFileListItem[], - maxSize: number | string + maxSize: UploaderMaxSize ) { const valid: UploaderFileListItem[] = []; const invalid: UploaderFileListItem[] = []; items.forEach((item) => { - if (item.file && item.file.size > maxSize) { + if (isOversize(item, maxSize)) { invalid.push(item); } else { valid.push(item);