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);