Skip to content

Commit

Permalink
feat(uploader): 微信小程序支持上传视频文件、录制时长等功能 #2119
Browse files Browse the repository at this point in the history
  • Loading branch information
richard1015 committed Feb 23, 2023
1 parent f9c3a4c commit 1978e6a
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 72 deletions.
51 changes: 29 additions & 22 deletions src/packages/__VUE/uploader/doc.taro.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ app.use(Uploader);
``` html
<nut-uploader :url="uploadUrl" :source-type="['camera']" ></nut-uploader>
```
### 使用前摄像头拍摄3s视频并上传(仅支持微信小程序)

``` html
<nut-uploader max-duration="3" :source-type="['camera']" camera="front" :url="uploadUrl"></nut-uploader>
```

### 限制上传数量5个

Expand Down Expand Up @@ -228,28 +233,30 @@ setup() {
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
|-------------------|------------------------------------------------------------------------------------------------------------------|-----------------------------------|-----------------------------|
| auto-upload | 是否在选取文件后立即进行上传,`false` 时需要手动执行 ref submit 方法进行上传 | boolean | `true` |
| name | 发到后台的文件参数名 | string | `file` |
| url | 上传服务器的接口地址 | string | `-` |
| v-model:file-list | 默认已经上传的文件列表 | FileItem[] | `[]` |
| is-preview | 是否上传成功后展示预览图 | boolean | `true` |
| is-deletable | 是否展示删除按钮 | boolean | `true` |
| method | 上传请求的 http method | string | `post` |
| list-type | 上传列表的内建样式,支持两种基础样式 `picture``list` | string | `picture` |
| source-type | [选择图片的来源](https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html) | string | `['album','camera']` |
| maximize | 可以设定最大上传文件的大小(字节) | number \| string | `9` |
| maximum | 文件上传数量限制 | number \| string | `1` |
| size-type | 是否压缩所选文件[详细说明](https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html) | string | `['original','compressed']` |
| headers | 设置上传的请求头部 | object | `{}` |
| data | 附加上传的信息 formData | object | `{}` |
| xhr-state | 接口响应的成功状态(status)值 | number | `200` |
| disabled | 是否禁用文件上传 | boolean | `false` |
| multiple | 是否支持文件多选 | boolean | `true` |
| timeout | 超时时间,单位为毫秒 | number \| string | `1000 * 30` |
| before-upload | 上传前的函数需要返回一个`Promise`对象 | Function | `null` |
| before-xhr-upload | 执行 Taro.uploadFile 上传时,自定义方式 | Function(Taro.uploadFile,option) | `null` |
| 参数 | 说明 | 类型 | 默认值 |
|---------------------------|----------------------------------------------------------------------------------------------------------|-----------------------------------|-----------------------------|
| auto-upload | 是否在选取文件后立即进行上传,`false` 时需要手动执行 ref submit 方法进行上传 | Boolean | `true` |
| name | 发到后台的文件参数名 | String | `file` |
| url | 上传服务器的接口地址 | String | `-` |
| v-model:file-list | 默认已经上传的文件列表 | FileItem[] | `[]` |
| is-preview | 是否上传成功后展示预览图 | Boolean | `true` |
| is-deletable | 是否展示删除按钮 | Boolean | `true` |
| method | 上传请求的 http method | String | `post` |
| list-type | 上传列表的内建样式,支持两种基础样式 `picture``list` | String | `picture` |
| maximize | 可以设定最大上传文件的大小(字节) | Number \| String | `Number.MAX_VALUE` |
| maximum | 最多可以选择的文件个数,微信基础库2.25.0前,最多可支持9个文件,2.25.0及以后最多可支持20个文件 | Number \| String | `1` |
| source-type | [选择文件的来源](https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseMedia.html) | Array | `['album','camera']` |
| camera`仅支持WEAPP` | 仅在 `source-type``camera` 时生效,使用前置或后置摄像头 | String | `back` |
| size-type | [是否压缩所选文件](https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseMedia.html) | Array | `['original','compressed']` |
| media-type`仅支持WEAPP` | [选择文件类型](https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseMedia.html) | Array | `['image', 'video', 'mix']` |
| max-duration`仅支持WEAPP` | 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 60s 之间。不限制相册。 | Number | 10 |
| headers | 设置上传的请求头部 | object | `{}` |
| data | 附加上传的信息 formData | object | `{}` |
| xhr-state | 接口响应的成功状态(status)值 | Number | `200` |
| disabled | 是否禁用文件上传 | Boolean | `false` |
| multiple | 是否支持文件多选 | Boolean | `true` |
| timeout | 超时时间,单位为毫秒 | Number \| String | `1000 * 30` |
| before-xhr-upload | 执行 `Taro.uploadFile` 上传时,自定义方式 | Function(Taro.uploadFile,option) | `null` |
### FileItem
Expand Down
138 changes: 90 additions & 48 deletions src/packages/__VUE/uploader/index.taro.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
class="nut-uploader__preview-img__c"
mode="aspectFit"
@click="fileItemClick(item)"
v-if="item.type?.includes('image') && item.url"
v-if="['image','video'].includes(item.type as string) && item.url"
:src="item.url"
/>
<view v-else class="nut-uploader__preview-img__file">
Expand Down Expand Up @@ -74,7 +74,7 @@
import { computed, PropType, reactive } from 'vue';
import { createComponent } from '@/packages/utils/create';
import { UploaderTaro, UploadOptions } from './uploader';
import { FileItem, SizeType, SourceType } from './type';
import { FileItem, MediaType, SizeType, SourceType } from './type';
import { funInterceptor, Interceptor } from '@/packages/utils/util';
import Progress from '../progress/index.taro.vue';
import Button from '../button/index.taro.vue';
Expand Down Expand Up @@ -102,6 +102,15 @@ export default create({
type: Array as PropType<SourceType[]>,
default: () => ['album', 'camera']
},
mediaType: {
type: Array as PropType<MediaType[]>,
default: () => ['image', 'video', 'mix']
},
camera: {
type: String,
default: 'back'
},
timeout: { type: [Number, String], default: 1000 * 30 },
// defaultFileList: { type: Array, default: () => new Array<FileItem>() },
fileList: { type: Array, default: () => [] },
Expand All @@ -121,10 +130,7 @@ export default create({
multiple: { type: Boolean, default: true },
disabled: { type: Boolean, default: false },
autoUpload: { type: Boolean, default: true },
beforeUpload: {
type: Function,
default: null
},
maxDuration: { type: Number, default: 10 },
beforeXhrUpload: {
type: Function,
default: null
Expand Down Expand Up @@ -177,17 +183,59 @@ export default create({
document.body.appendChild(obj);
}
}
if (Taro.getEnv() == 'WEAPP') {
// chooseMedia 目前只支持微信小程序原生,其余端全部使用 chooseImage API
Taro.chooseMedia({
/** 最多可以选择的文件个数 */
count: props.multiple ? (props.maximum as number) * 1 - props.fileList.length : 1,
/** 文件类型 */
mediaType: props.mediaType,
/** 图片和视频选择的来源 */
sourceType: props.sourceType,
/** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 30s 之间 */
maxDuration: props.maxDuration,
/** 仅对 mediaType 为 image 时有效,是否压缩所选文件 */
sizeType: [],
/** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 */
camera: props.camera,
/** 接口调用失败的回调函数 */
fail: (res: TaroGeneral.CallbackResult) => {
emit('failure', res);
},
/** 接口调用成功的回调函数 */
success: onChangeMedia
});
} else {
Taro.chooseImage({
// 选择数量
count: props.multiple ? (props.maximum as number) * 1 - props.fileList.length : 1,
// 可以指定是原图还是压缩图,默认二者都有
sizeType: props.sizeType,
sourceType: props.sourceType,
success: onChangeImage,
fail: (res: any) => {
emit('failure', res);
}
});
}
};
Taro.chooseImage({
// 选择数量
count: props.multiple ? (props.maximum as number) * 1 - props.fileList.length : 1,
// 可以指定是原图还是压缩图,默认二者都有
sizeType: props.sizeType,
sourceType: props.sourceType,
success: onChange,
fail: (res: any) => {
emit('failure', res);
}
const onChangeMedia = (res: Taro.chooseMedia.SuccessCallbackResult) => {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
const { type, tempFiles } = res;
const _files: Taro.chooseMedia.ChooseMedia[] = filterFiles<Taro.chooseMedia.ChooseMedia>(tempFiles);
readFile<Taro.chooseMedia.ChooseMedia>(_files);
emit('change', {
fileList
});
};
const onChangeImage = (res: Taro.chooseImage.SuccessCallbackResult) => {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
const { tempFilePaths, tempFiles } = res;
const _files: Taro.chooseImage.ImageFile[] = filterFiles<Taro.chooseImage.ImageFile>(tempFiles);
readFile<Taro.chooseImage.ImageFile>(_files);
emit('change', {
fileList
});
};
Expand Down Expand Up @@ -267,17 +315,31 @@ export default create({
res.forEach((i) => i.uploadTaro(Taro.uploadFile, Taro.getEnv()));
});
};
const readFile = (files: Taro.chooseImage.ImageFile[]) => {
const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i;
files.forEach((file: Taro.chooseImage.ImageFile, index: number) => {
interface TFileType {
size: number;
type?: string;
fileType?: string;
originalFileObj?: any;
tempFilePath?: string;
thumbTempFilePath?: string;
path?: string;
}
const readFile = <T extends TFileType>(files: T[]) => {
files.forEach((file: T, index: number) => {
let fileType = file.type;
let filepath = (file.tempFilePath || file.path) as string;
const fileItem = reactive(new FileItem());
if (!fileType && (imgReg.test(file.path) || file.path.includes('data:image'))) {
fileType = 'image';
if (file.fileType) {
fileType = file.fileType;
} else {
const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i;
if (!fileType && (imgReg.test(filepath) || filepath.includes('data:image'))) {
fileType = 'image';
}
}
fileItem.path = file.path;
fileItem.name = file.path;
fileItem.path = filepath;
fileItem.name = filepath;
fileItem.status = 'ready';
fileItem.message = translate('waitingUpload');
fileItem.type = fileType;
Expand All @@ -294,18 +356,18 @@ export default create({
fileItem.formData = props.data;
}
if (props.isPreview) {
fileItem.url = file.path;
fileItem.url = fileType == 'video' ? file.thumbTempFilePath : filepath;
}
fileList.push(fileItem);
executeUpload(fileItem, index);
});
};
const filterFiles = (files: Taro.chooseImage.ImageFile[]) => {
const filterFiles = <T extends TFileType>(files: T[]) => {
const maximum = (props.maximum as number) * 1;
const maximize = (props.maximize as number) * 1;
const oversizes = new Array<Taro.chooseImage.ImageFile>();
files = files.filter((file: Taro.chooseImage.ImageFile) => {
const oversizes = new Array<T>();
files = files.filter((file: T) => {
if (file.size > maximize) {
oversizes.push(file);
return false;
Expand Down Expand Up @@ -340,26 +402,6 @@ export default create({
});
};
const onChange = (res: Taro.chooseImage.SuccessCallbackResult) => {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
const { tempFilePaths, tempFiles } = res;
if (props.beforeUpload) {
props.beforeUpload(tempFiles).then((f: Array<Taro.chooseImage.ImageFile>) => changeReadFile(f));
} else {
changeReadFile(tempFiles);
}
emit('change', {
fileList
});
};
const changeReadFile = (f: any) => {
const _files: Taro.chooseImage.ImageFile[] = filterFiles(f);
readFile(_files);
};
return {
onDelete,
fileList,
Expand Down
3 changes: 2 additions & 1 deletion src/packages/__VUE/uploader/type.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createComponent } from '@/packages/utils/create';
const { translate } = createComponent('uploader');
export type SizeType = 'original' | 'compressed';
export type SourceType = 'album' | 'camera' | 'user' | 'environment';
export type SourceType = 'album' | 'camera';
export type MediaType = 'image' | 'video' | 'mix';
export type FileItemStatus = 'ready' | 'uploading' | 'success' | 'error';
export class FileItem {
status: FileItemStatus = 'ready';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@
<!--
album 从相册选图
camera 使用相机
user 使用前置摄像头(仅H5纯浏览器使用)
environment 使用后置摄像头(仅H5纯浏览器)
-->
<h2>直接调起摄像头 camera </h2>
<nut-uploader :source-type="['camera']"></nut-uploader>
<h2>使用前摄像头拍摄3s视频并上传(仅支持微信小程序)</h2>
<nut-uploader max-duration="3" :source-type="['camera']" camera="front" :url="uploadUrl"></nut-uploader>
<h2>上传状态</h2>
<nut-uploader :url="uploadUrl" @delete="onDelete"></nut-uploader>
<h2>限制上传数量5个</h2>
Expand Down

0 comments on commit 1978e6a

Please sign in to comment.