add file
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
:: BASE_DOC ::
|
||||
|
||||
## API
|
||||
### Upload Props
|
||||
|
||||
name | type | default | description | required
|
||||
-- | -- | -- | -- | --
|
||||
add-content | String / Slot | - | \- | N
|
||||
allow-upload-duplicate-file | Boolean | false | \- | N
|
||||
config | Object | - | Typescript:`UploadMpConfig` `type UploadMpConfig = ImageConfig \| VideoConfig` `interface ImageConfig { count?: number; sizeType?: Array<SizeTypeValues>; sourceType?: Array<SourceTypeValues> }` `type SizeTypeValues = 'original' \| 'compressed'` `type SourceTypeValues = 'album' \| 'camera'` `interface VideoConfig { sourceType?: Array<SourceTypeValues>; compressed?: boolean; maxDuration?: number; camera?: 'back' \| 'front' }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
custom-style | String | - | \- | N
|
||||
file-list-display | Slot | - | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
files | Array | - | Typescript:`Array<UploadFile>` `interface UploadFile { url: string; name?: string; size?: number; type?: 'image' \| 'video'; percent?: number; status: 'loading' \| 'reload' \| 'failed' \| 'done' }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
default-files | Array | undefined | uncontrolled property。Typescript:`Array<UploadFile>` `interface UploadFile { url: string; name?: string; size?: number; type?: 'image' \| 'video'; percent?: number; status: 'loading' \| 'reload' \| 'failed' \| 'done' }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
grid-config | Object | - | Typescript:`{column?: number; width?: number; height?: number;}` | N
|
||||
gutter | Number | 16 | \- | N
|
||||
image-props | Object | - | Typescript:`ImageProps`,[Image API Documents](./image?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
max | Number | 0 | \- | N
|
||||
media-type | Array | ['image', 'video'] | Typescript:`Array<MediaType>` `type MediaType = 'image' \| 'video'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
request-method | Function | - | \- | N
|
||||
size-limit | Number / Object | - | Typescript:`number \| SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
source | String | media | options:media/messageFile | N
|
||||
|
||||
### Upload Events
|
||||
|
||||
name | params | description
|
||||
-- | -- | --
|
||||
add | `(files: MediaContext)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts)。<br/>`type MediaContext = VideoContext[] \| ImageContext[]`<br/><br/>`interface VideoContext { name?: string; type?: string; url?: string; duration?: number; size?: number; width?: number; height?: number; thumb: string; progress: number }`<br/><br/>`interface ImageContext { name: string; type: string; url: string; size: number; width: number; height: number; progress: number }`<br/>
|
||||
complete | \- | \-
|
||||
fail | \- | \-
|
||||
remove | `(index: number; file: UploadFile)` | \-
|
||||
select-change | `(currentSelectedFiles: MediaContext[])` | \-
|
||||
success | `(files: MediaContext)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts)。<br/>`type MediaContext = VideoContext[] \| ImageContext[]`<br/><br/>`interface VideoContext { name?: string; type?: string; url?: string; duration?: number; size?: number; width?: number; height?: number; thumb: string; progress: number }`<br/><br/>`interface ImageContext { name: string; type: string; url: string; size: number; width: number; height: number; progress: number }`<br/>
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Upload 上传
|
||||
description: 用于相册读取或拉起拍照的图片上传功能。
|
||||
spline: form
|
||||
isComponent: true
|
||||
---
|
||||
|
||||
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-90%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-83%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-89%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-81%25-blue" /></span>
|
||||
## 引入
|
||||
|
||||
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
|
||||
|
||||
```json
|
||||
"usingComponents": {
|
||||
"t-upload": "tdesign-miniprogram/upload/upload",
|
||||
}
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 单选上传图片
|
||||
|
||||
图片上传有两种方式:
|
||||
|
||||
1 选择完所有图片之后,统一上传,因此选择完就直接展示
|
||||
|
||||
2 每次选择图片都上传,展示每次上传图片的进度
|
||||
|
||||
{{ single }}
|
||||
|
||||
### 多选上传图片
|
||||
|
||||
{{ multiple }}
|
||||
|
||||
### 加载状态
|
||||
|
||||
支持多种状态:`loading`、`reload`、`failed`;
|
||||
|
||||
其中 `loading` 还可以通过传入 `percent` 来区分是否展示进度。
|
||||
|
||||
{{ status }}
|
||||
|
||||
### 从聊天记录上选
|
||||
|
||||
使用 `wx.chooseMessageFile` 实现,需要基础版本库 `2.5.0+`
|
||||
|
||||
{{ messageFile }}
|
||||
|
||||
## API
|
||||
### Upload Props
|
||||
|
||||
名称 | 类型 | 默认值 | 说明 | 必传
|
||||
-- | -- | -- | -- | --
|
||||
add-content | String / Slot | - | 添加按钮内容。值为空,使用默认图标渲染;值为 slot 则表示使用插槽渲染;其他值无效。 | N
|
||||
allow-upload-duplicate-file | Boolean | false | 【开发中】是否允许重复上传相同文件名的文件 | N
|
||||
config | Object | - | 图片上传配置,视频上传配置,文件上传配置等,包含图片尺寸、图片来源、视频来源、视频拍摄最长时间等。更多细节查看小程序官网。[图片上传](https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html)。[视频上传](https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseVideo.html)。TS 类型:`UploadMpConfig` `type UploadMpConfig = ImageConfig \| VideoConfig` `interface ImageConfig { count?: number; sizeType?: Array<SizeTypeValues>; sourceType?: Array<SourceTypeValues> }` `type SizeTypeValues = 'original' \| 'compressed'` `type SourceTypeValues = 'album' \| 'camera'` `interface VideoConfig { sourceType?: Array<SourceTypeValues>; compressed?: boolean; maxDuration?: number; camera?: 'back' \| 'front' }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
custom-style `v0.25.0` | String | - | 自定义组件样式 | N
|
||||
file-list-display | Slot | - | 【开发中】用于完全自定义文件列表内容。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
files | Array | - | 已上传文件列表。TS 类型:`Array<UploadFile>` `interface UploadFile { url: string; name?: string; size?: number; type?: 'image' \| 'video'; percent?: number; status: 'loading' \| 'reload' \| 'failed' \| 'done' }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
default-files | Array | undefined | 已上传文件列表。非受控属性。TS 类型:`Array<UploadFile>` `interface UploadFile { url: string; name?: string; size?: number; type?: 'image' \| 'video'; percent?: number; status: 'loading' \| 'reload' \| 'failed' \| 'done' }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
grid-config | Object | - | upload组件每行上传图片列数以及图片的宽度和高度。TS 类型:`{column?: number; width?: number; height?: number;}` | N
|
||||
gutter | Number | 16 | 预览窗格的 `gutter` 大小,单位 rpx | N
|
||||
image-props | Object | - | 透传 Image 组件全部属性。TS 类型:`ImageProps`,[Image API Documents](./image?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
max | Number | 0 | 用于控制文件上传数量,值为 0 则不限制 | N
|
||||
media-type | Array | ['image', 'video'] | 支持上传的文件类型,图片或视频。TS 类型:`Array<MediaType>` `type MediaType = 'image' \| 'video'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
request-method | Function | - | 自定义上传方法 | N
|
||||
size-limit | Number / Object | - | 图片文件大小限制,单位 KB。可选单位有:`'B' \| 'KB' \| 'MB' \| 'GB'`。示例一:`1000`。示例二:`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`。TS 类型:`number \| SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts) | N
|
||||
source | String | media | 来源。可选项:media/messageFile | N
|
||||
|
||||
### Upload Events
|
||||
|
||||
名称 | 参数 | 描述
|
||||
-- | -- | --
|
||||
add | `(files: MediaContext)` | 选择后触发,仅包含本次选择的照片;`url` 表示选定视频的临时文件路径 (本地路径)。`duration` 表示选定视频的时间长度。`size`选定视频的数据量大小。更多描述参考 wx.chooseMedia 小程序官网描述。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts)。<br/>`type MediaContext = VideoContext[] \| ImageContext[]`<br/><br/>`interface VideoContext { name?: string; type?: string; url?: string; duration?: number; size?: number; width?: number; height?: number; thumb: string; progress: number }`<br/><br/>`interface ImageContext { name: string; type: string; url: string; size: number; width: number; height: number; progress: number }`<br/>
|
||||
complete | \- | 上传成功或失败后触发
|
||||
fail | \- | 上传失败后触发
|
||||
remove | `(index: number; file: UploadFile)` | 移除文件时触发
|
||||
select-change | `(files: MediaContext[]; currentSelectedFiles: MediaContext[])` | 选择文件或图片之后,上传之前,触发该事件。<br />`files` 表示之前已经上传完成的文件列表。<br />`currentSelectedFiles` 表示本次上传选中的文件列表
|
||||
success | `(files: MediaContext)` | 上传成功后触发,包含所有上传的文件;`url` 表示选定视频的临时文件路径 (本地路径)。`duration` 表示选定视频的时间长度。`size`选定视频的数据量大小。更多描述参考 wx.chooseMedia 小程序官网描述。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/upload/type.ts)。<br/>`type MediaContext = VideoContext[] \| ImageContext[]`<br/><br/>`interface VideoContext { name?: string; type?: string; url?: string; duration?: number; size?: number; width?: number; height?: number; thumb: string; progress: number }`<br/><br/>`interface ImageContext { name: string; type: string; url: string; size: number; width: number; height: number; progress: number }`<br/>
|
||||
click | `(file: VideoContext | ImageContext)` | 点击已选文件时触发;常用于重新上传
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import { TdUploadProps } from './type';
|
||||
declare const props: TdUploadProps;
|
||||
export default props;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
const props = {
|
||||
addContent: {
|
||||
type: String,
|
||||
},
|
||||
allowUploadDuplicateFile: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
},
|
||||
customStyle: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
files: {
|
||||
type: Array,
|
||||
value: null,
|
||||
},
|
||||
defaultFiles: {
|
||||
type: Array,
|
||||
},
|
||||
gridConfig: {
|
||||
type: Object,
|
||||
},
|
||||
gutter: {
|
||||
type: Number,
|
||||
value: 16,
|
||||
},
|
||||
imageProps: {
|
||||
type: Object,
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
mediaType: {
|
||||
type: Array,
|
||||
value: ['image', 'video'],
|
||||
},
|
||||
requestMethod: {
|
||||
type: null,
|
||||
},
|
||||
sizeLimit: {
|
||||
type: null,
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
value: 'media',
|
||||
},
|
||||
};
|
||||
export default props;
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
import { ImageProps } from '../image/index';
|
||||
export interface TdUploadProps {
|
||||
addContent?: {
|
||||
type: StringConstructor;
|
||||
value?: string;
|
||||
};
|
||||
allowUploadDuplicateFile?: {
|
||||
type: BooleanConstructor;
|
||||
value?: boolean;
|
||||
};
|
||||
config?: {
|
||||
type: ObjectConstructor;
|
||||
value?: UploadMpConfig;
|
||||
};
|
||||
customStyle?: {
|
||||
type: StringConstructor;
|
||||
value?: string;
|
||||
};
|
||||
files?: {
|
||||
type: ArrayConstructor;
|
||||
value?: Array<UploadFile>;
|
||||
};
|
||||
defaultFiles?: {
|
||||
type: ArrayConstructor;
|
||||
value?: Array<UploadFile>;
|
||||
};
|
||||
gridConfig?: {
|
||||
type: ObjectConstructor;
|
||||
value?: {
|
||||
column?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
};
|
||||
};
|
||||
gutter?: {
|
||||
type: NumberConstructor;
|
||||
value?: number;
|
||||
};
|
||||
imageProps?: {
|
||||
type: ObjectConstructor;
|
||||
value?: ImageProps;
|
||||
};
|
||||
max?: {
|
||||
type: NumberConstructor;
|
||||
value?: number;
|
||||
};
|
||||
mediaType?: {
|
||||
type: ArrayConstructor;
|
||||
value?: Array<MediaType>;
|
||||
};
|
||||
requestMethod?: {
|
||||
type: null;
|
||||
value?: null;
|
||||
};
|
||||
sizeLimit?: {
|
||||
type: null;
|
||||
value?: number | SizeLimitObj;
|
||||
};
|
||||
source?: {
|
||||
type: StringConstructor;
|
||||
value?: 'media' | 'messageFile';
|
||||
};
|
||||
}
|
||||
export declare type UploadMpConfig = ImageConfig | VideoConfig;
|
||||
export interface ImageConfig {
|
||||
count?: number;
|
||||
sizeType?: Array<SizeTypeValues>;
|
||||
sourceType?: Array<SourceTypeValues>;
|
||||
}
|
||||
export declare type SizeTypeValues = 'original' | 'compressed';
|
||||
export declare type SourceTypeValues = 'album' | 'camera';
|
||||
export interface VideoConfig {
|
||||
sourceType?: Array<SourceTypeValues>;
|
||||
compressed?: boolean;
|
||||
maxDuration?: number;
|
||||
camera?: 'back' | 'front';
|
||||
}
|
||||
export interface UploadDisplayDragEvents {
|
||||
onDrop?: (event: DragEvent) => void;
|
||||
onDragenter?: (event: DragEvent) => void;
|
||||
onDragover?: (event: DragEvent) => void;
|
||||
onDragleave?: (event: DragEvent) => void;
|
||||
}
|
||||
export interface UploadFile {
|
||||
url: string;
|
||||
name?: string;
|
||||
size?: number;
|
||||
type?: 'image' | 'video';
|
||||
percent?: number;
|
||||
status: 'loading' | 'reload' | 'failed' | 'done';
|
||||
}
|
||||
export declare type MediaType = 'image' | 'video';
|
||||
export interface SizeLimitObj {
|
||||
size: number;
|
||||
unit: SizeUnit;
|
||||
message?: string;
|
||||
}
|
||||
export declare type SizeUnitArray = ['B', 'KB', 'MB', 'GB'];
|
||||
export declare type SizeUnit = SizeUnitArray[number];
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"key": "Upload",
|
||||
"label": "上传",
|
||||
"icon": "",
|
||||
"properties": [
|
||||
{
|
||||
"key": "addContent",
|
||||
"type": ["String", "TNode"],
|
||||
"defaultValue": "",
|
||||
"desc": "添加按钮内容。值为空,使用默认图标渲染;值为 slot 则表示使用插槽渲染;其他值无效。",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "config",
|
||||
"type": ["Object"],
|
||||
"defaultValue": "",
|
||||
"desc": "图片上传配置,视频上传配置,文件上传配置等,包含图片尺寸、图片来源、视频来源、视频拍摄最长时间等。更多细节查看小程序官网。[图片上传](https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html)。[视频上传](https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseVideo.html)",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "deleteBtn",
|
||||
"type": ["String", "TNode"],
|
||||
"defaultValue": "",
|
||||
"desc": "删除图标。值为空,使用默认图标渲染;值为 slot 则表示使用插槽渲染;其他值无效。",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "fileListDisplay",
|
||||
"type": ["TNode"],
|
||||
"defaultValue": "",
|
||||
"desc": "【开发中】用于完全自定义文件列表内容",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "files",
|
||||
"type": ["Array"],
|
||||
"defaultValue": "",
|
||||
"desc": "已上传文件列表",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "gridConfig",
|
||||
"type": ["Object"],
|
||||
"defaultValue": "",
|
||||
"desc": "upload组件每行上传图片列数以及图片的宽度和高度",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "gutter",
|
||||
"type": ["Number"],
|
||||
"defaultValue": "16",
|
||||
"desc": "预览窗格的 gutter 大小,单位 rpx",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "imageProps",
|
||||
"type": ["Object"],
|
||||
"defaultValue": "",
|
||||
"desc": "透传 Image 组件全部属性",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "max",
|
||||
"type": ["Number"],
|
||||
"defaultValue": "0",
|
||||
"desc": "用于控制文件上传数量,值为 0 则不限制",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "mediaType",
|
||||
"type": ["Array"],
|
||||
"defaultValue": "['image', 'video']",
|
||||
"desc": "支持上传的文件类型,图片或视频",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "requestMethod",
|
||||
"type": ["Function"],
|
||||
"defaultValue": "",
|
||||
"desc": "自定义上传方法",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "sizeLimit",
|
||||
"type": ["Number", "Object"],
|
||||
"defaultValue": "",
|
||||
"desc": "图片文件大小限制,单位 KB。可选单位有:`'B' | 'KB' | 'MB' | 'GB'`。示例一:`1000`。示例二:`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`",
|
||||
"label": ""
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"key": "add",
|
||||
"desc": "上传成功后触发,仅包含本次选择的照片;`context.url` 表示选定视频的临时文件路径 (本地路径)。`context.duration` 表示选定视频的时间长度。`context.size`选定视频的数据量大小。更多描述参考 wx.chooseMedia 小程序官网描述",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "complete",
|
||||
"desc": "上传成功或失败后触发",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "fail",
|
||||
"desc": "上传失败后触发",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "remove",
|
||||
"desc": "移除文件时触发",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "selectChange",
|
||||
"desc": "选择文件或图片之后,上传之前,触发该事件。<br />`params.value` 表示之前已经上传完成的文件列表。<br />`params.currentSelectedFiles` 表示本次上传选中的文件列表",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"key": "success",
|
||||
"desc": "上传成功后触发,包含所有上传的文件;`context.url` 表示选定视频的临时文件路径 (本地路径)。`context.duration` 表示选定视频的时间长度。`context.size`选定视频的数据量大小。更多描述参考 wx.chooseMedia 小程序官网描述",
|
||||
"label": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { SuperComponent } from '../common/src/index';
|
||||
import { UploadMpConfig, UploadFile } from './type';
|
||||
export default class Upload extends SuperComponent {
|
||||
externalClasses: string[];
|
||||
options: {
|
||||
multipleSlots: boolean;
|
||||
};
|
||||
data: {
|
||||
classPrefix: string;
|
||||
prefix: string;
|
||||
current: boolean;
|
||||
proofs: any[];
|
||||
customFiles: UploadFile[];
|
||||
customLimit: number;
|
||||
config: UploadMpConfig;
|
||||
files: UploadFile[];
|
||||
max: number;
|
||||
sizeLimit: number;
|
||||
requestMethod: any;
|
||||
gridItemStyle: string;
|
||||
column: number;
|
||||
};
|
||||
properties: import("./type").TdUploadProps;
|
||||
controlledProps: {
|
||||
key: string;
|
||||
event: string;
|
||||
}[];
|
||||
observers: {
|
||||
files(files: UploadFile): void;
|
||||
max(max: any): void;
|
||||
gridConfig(): void;
|
||||
};
|
||||
onProofTap(e: any): void;
|
||||
ready(): void;
|
||||
handleLimit(customFiles: UploadFile[], max: number): void;
|
||||
uploadFiles(files: UploadFile[]): Promise<unknown>;
|
||||
startUpload(files: UploadFile[]): Promise<void>;
|
||||
triggerSuccessEvent(files: any): void;
|
||||
triggerFailEvent(err: any): void;
|
||||
onFileClick(e: any): void;
|
||||
getFileType(mediaType: string[], tempFilePath: string, fileType?: string): string;
|
||||
getRandFileName(filePath: any): string;
|
||||
onDelete(e: any): void;
|
||||
deleteHandle(index: number): void;
|
||||
updateGrid(): void;
|
||||
methods: {
|
||||
onAddTap(): void;
|
||||
chooseMedia(mediaType: any): void;
|
||||
chooseMessageFile(mediaType: any): void;
|
||||
afterSelect(files: any): void;
|
||||
};
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import { isObject, SuperComponent, wxComponent } from '../common/src/index';
|
||||
import props from './props';
|
||||
import config from '../common/config';
|
||||
const { prefix } = config;
|
||||
const name = `${prefix}-upload`;
|
||||
let Upload = class Upload extends SuperComponent {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.externalClasses = [`${prefix}-class`];
|
||||
this.options = {
|
||||
multipleSlots: true,
|
||||
};
|
||||
this.data = {
|
||||
classPrefix: name,
|
||||
prefix,
|
||||
current: false,
|
||||
proofs: [],
|
||||
customFiles: [],
|
||||
customLimit: 0,
|
||||
config: {},
|
||||
files: [],
|
||||
max: 0,
|
||||
sizeLimit: 0,
|
||||
requestMethod: null,
|
||||
gridItemStyle: '',
|
||||
column: 4,
|
||||
};
|
||||
this.properties = props;
|
||||
this.controlledProps = [
|
||||
{
|
||||
key: 'files',
|
||||
event: 'success',
|
||||
},
|
||||
];
|
||||
this.observers = {
|
||||
files(files) {
|
||||
this.handleLimit(files, this.data.max);
|
||||
},
|
||||
max(max) {
|
||||
this.handleLimit(this.data.customFiles, max);
|
||||
},
|
||||
gridConfig() {
|
||||
this.updateGrid();
|
||||
},
|
||||
};
|
||||
this.methods = {
|
||||
onAddTap() {
|
||||
const { mediaType, source } = this.properties;
|
||||
if (source === 'media') {
|
||||
this.chooseMedia(mediaType);
|
||||
}
|
||||
else {
|
||||
this.chooseMessageFile(mediaType);
|
||||
}
|
||||
},
|
||||
chooseMedia(mediaType) {
|
||||
const { config, sizeLimit, max } = this.data;
|
||||
wx.chooseMedia(Object.assign(Object.assign({ count: max === 0 ? 9 : max, mediaType }, config), { success: (res) => {
|
||||
const files = [];
|
||||
res.tempFiles.forEach((temp) => {
|
||||
const { size, fileType, tempFilePath, width, height, duration, thumbTempFilePath } = temp, res = __rest(temp, ["size", "fileType", "tempFilePath", "width", "height", "duration", "thumbTempFilePath"]);
|
||||
if (sizeLimit && size > sizeLimit) {
|
||||
wx.showToast({ icon: 'none', title: `${fileType === 'image' ? '图片' : '视频'}大小超过限制` });
|
||||
return;
|
||||
}
|
||||
const name = this.getRandFileName(tempFilePath);
|
||||
files.push(Object.assign({ name, type: this.getFileType(mediaType, tempFilePath, fileType), url: tempFilePath, size: size, width: width, height: height, duration: duration, thumb: thumbTempFilePath, percent: 0 }, res));
|
||||
});
|
||||
this.afterSelect(files);
|
||||
}, fail: (err) => {
|
||||
this.triggerFailEvent(err);
|
||||
}, complete: (res) => {
|
||||
this.triggerEvent('complete', res);
|
||||
} }));
|
||||
},
|
||||
chooseMessageFile(mediaType) {
|
||||
const { max, config, sizeLimit } = this.properties;
|
||||
wx.chooseMessageFile(Object.assign(Object.assign({ count: max, type: Array.isArray(mediaType) ? 'all' : mediaType }, config), { success: (res) => {
|
||||
const files = [];
|
||||
res.tempFiles.forEach((temp) => {
|
||||
const { size, type: fileType, path: tempFilePath } = temp, res = __rest(temp, ["size", "type", "path"]);
|
||||
if (sizeLimit && size > sizeLimit) {
|
||||
wx.showToast({ icon: 'none', title: `${fileType === 'image' ? '图片' : '视频'}大小超过限制` });
|
||||
return;
|
||||
}
|
||||
const name = this.getRandFileName(tempFilePath);
|
||||
files.push(Object.assign({ name, type: this.getFileType(mediaType, tempFilePath, fileType), url: tempFilePath, size: size, percent: 0 }, res));
|
||||
});
|
||||
this.afterSelect(files);
|
||||
}, fail: (err) => this.triggerFailEvent(err), complete: (res) => this.triggerEvent('complete', res) }));
|
||||
},
|
||||
afterSelect(files) {
|
||||
this._trigger('select-change', {
|
||||
files: [...this.data.customFiles],
|
||||
currentSelectedFiles: [files],
|
||||
});
|
||||
this._trigger('add', { files });
|
||||
this.startUpload(files);
|
||||
},
|
||||
};
|
||||
}
|
||||
onProofTap(e) {
|
||||
var _a;
|
||||
const { index } = e.currentTarget.dataset;
|
||||
wx.previewImage({
|
||||
urls: this.data.customFiles.filter((file) => file.percent !== -1).map((file) => file.url),
|
||||
current: (_a = this.data.customFiles[index]) === null || _a === void 0 ? void 0 : _a.url,
|
||||
});
|
||||
}
|
||||
ready() {
|
||||
this.handleLimit(this.data.customFiles, this.data.max);
|
||||
this.updateGrid();
|
||||
}
|
||||
handleLimit(customFiles, max) {
|
||||
while (max !== 0 && customFiles.length - max > 0) {
|
||||
customFiles.pop();
|
||||
}
|
||||
const proofs = [];
|
||||
customFiles.forEach((item) => {
|
||||
if (item.type !== 'video') {
|
||||
proofs.push(item.url);
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
customFiles,
|
||||
proofs,
|
||||
customLimit: max === 0 ? Number.MAX_SAFE_INTEGER : max - customFiles.length,
|
||||
});
|
||||
}
|
||||
uploadFiles(files) {
|
||||
return new Promise((resolve) => {
|
||||
const task = this.data.requestMethod(files);
|
||||
if (task instanceof Promise) {
|
||||
return task;
|
||||
}
|
||||
resolve({});
|
||||
});
|
||||
}
|
||||
startUpload(files) {
|
||||
if (typeof this.data.requestMethod === 'function') {
|
||||
return this.uploadFiles(files)
|
||||
.then(() => {
|
||||
files.forEach((file) => {
|
||||
file.percent = 100;
|
||||
});
|
||||
this.triggerSuccessEvent(files);
|
||||
})
|
||||
.catch((err) => {
|
||||
this.triggerFailEvent(err);
|
||||
});
|
||||
}
|
||||
this.triggerSuccessEvent(files);
|
||||
this.handleLimit(this.data.customFiles, this.data.max);
|
||||
return Promise.resolve();
|
||||
}
|
||||
triggerSuccessEvent(files) {
|
||||
this._trigger('success', { files: [...this.data.customFiles, ...files] });
|
||||
}
|
||||
triggerFailEvent(err) {
|
||||
this.triggerEvent('fail', err);
|
||||
}
|
||||
onFileClick(e) {
|
||||
const { file } = e.currentTarget.dataset;
|
||||
this.triggerEvent('click', { file });
|
||||
}
|
||||
getFileType(mediaType, tempFilePath, fileType) {
|
||||
if (fileType)
|
||||
return fileType;
|
||||
if (mediaType.length === 1) {
|
||||
return mediaType[0];
|
||||
}
|
||||
const videoType = ['avi', 'wmv', 'mkv', 'mp4', 'mov', 'rm', '3gp', 'flv', 'mpg', 'rmvb'];
|
||||
const temp = tempFilePath.split('.');
|
||||
const postfix = temp[temp.length - 1];
|
||||
if (videoType.includes(postfix.toLocaleLowerCase())) {
|
||||
return 'video';
|
||||
}
|
||||
return 'image';
|
||||
}
|
||||
getRandFileName(filePath) {
|
||||
const extIndex = filePath.lastIndexOf('.');
|
||||
const extName = extIndex === -1 ? '' : filePath.substr(extIndex);
|
||||
return parseInt(`${Date.now()}${Math.floor(Math.random() * 900 + 100)}`, 10).toString(36) + extName;
|
||||
}
|
||||
onDelete(e) {
|
||||
const { index } = e.currentTarget.dataset;
|
||||
this.deleteHandle(index);
|
||||
}
|
||||
deleteHandle(index) {
|
||||
const { customFiles } = this.data;
|
||||
const delFile = customFiles[index];
|
||||
this.triggerEvent('remove', { index, file: delFile });
|
||||
}
|
||||
updateGrid() {
|
||||
let { gridConfig = {} } = this.properties;
|
||||
if (!isObject(gridConfig))
|
||||
gridConfig = {};
|
||||
const { column = 4, width = 160, height = 160 } = gridConfig;
|
||||
this.setData({
|
||||
gridItemStyle: `width:${width}rpx;height:${height}rpx`,
|
||||
column: column,
|
||||
});
|
||||
}
|
||||
};
|
||||
Upload = __decorate([
|
||||
wxComponent()
|
||||
], Upload);
|
||||
export default Upload;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-grid": "../grid/grid",
|
||||
"t-grid-item": "../grid-item/grid-item",
|
||||
"t-popup": "../popup/popup",
|
||||
"t-icon": "../icon/icon",
|
||||
"t-image": "../image/image"
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<view style="{{ customStyle }}" class="{{classPrefix}} {{prefix}}-class">
|
||||
<t-grid gutter="{{gutter}}" border="{{false}}" align="center" column="{{column}}">
|
||||
<!-- 图片/视频 -->
|
||||
<t-grid-item
|
||||
wx:for="{{customFiles}}"
|
||||
wx:key="index"
|
||||
wx:for-item="file"
|
||||
t-class="{{classPrefix}}__grid {{classPrefix}}__grid-file"
|
||||
t-class-content="{{classPrefix}}__grid-content"
|
||||
>
|
||||
<view class="{{classPrefix}}__wrapper" style="{{gridItemStyle}}">
|
||||
<t-image
|
||||
wx:if="{{file.type !== 'video'}}"
|
||||
bindtap="onProofTap"
|
||||
data-index="{{index}}"
|
||||
t-class="{{classPrefix}}__thumbnail"
|
||||
src="{{file.url}}"
|
||||
mode="{{imageProps.mode}}"
|
||||
error="{{imageProps.error}}"
|
||||
lazy="{{imageProps.lazy}}"
|
||||
loading="{{imageProps.loading}}"
|
||||
shape="{{imageProps.shape || 'round'}}"
|
||||
webp="{{imageProps.webp}}"
|
||||
showMenuByLongpress="{{image.showMenuByLongpress}}"
|
||||
/>
|
||||
<video
|
||||
wx:if="{{file.type === 'video'}}"
|
||||
class="{{classPrefix}}__thumbnail"
|
||||
src="{{file.url}}"
|
||||
controls
|
||||
autoplay="{{false}}"
|
||||
objectFit="contain"
|
||||
/>
|
||||
<!-- 失败重试 -->
|
||||
<view
|
||||
data-index="{{index}}"
|
||||
wx:if="{{file.status && file.status != 'done'}}"
|
||||
class="{{classPrefix}}__progress-mask"
|
||||
data-file="{{file}}"
|
||||
bind:tap="onFileClick"
|
||||
>
|
||||
<block wx:if="{{file.status == 'loading'}}">
|
||||
<t-icon t-class="{{classPrefix}}__progress-loading" name="loading" size="24" />
|
||||
<view class="{{classPrefix}}__progress-text">{{file.percent ? file.percent + '%' : '上传中...'}}</view>
|
||||
</block>
|
||||
<t-icon wx:else name="{{file.status == 'reload' ? 'refresh' : 'close-circle'}}" size="24" />
|
||||
<view wx:if="{{file.status == 'reload' || file.status == 'failed'}}" class="{{classPrefix}}__progress-text"
|
||||
>{{file.status == 'reload' ? '重新上传' : '上传失败'}}</view
|
||||
>
|
||||
</view>
|
||||
<!-- 删除 -->
|
||||
<view class="{{classPrefix}}__close-btn hotspot-expanded" bindtap="onDelete" data-index="{{index}}">
|
||||
<slot wx:if="{{deleteBtn === 'slot'}}" name="delete-btn" />
|
||||
<t-icon wx:else name="close" size="16" color="#fff" />
|
||||
</view>
|
||||
</view>
|
||||
</t-grid-item>
|
||||
<!-- 添加 -->
|
||||
<t-grid-item
|
||||
wx:if="{{customLimit > 0}}"
|
||||
t-class="{{classPrefix}}__grid"
|
||||
t-class-content="{{classPrefix}}__grid-content"
|
||||
bindclick="onAddTap"
|
||||
>
|
||||
<view class="{{classPrefix}}__wrapper" style="{{gridItemStyle}}">
|
||||
<view class="{{classPrefix}}__add-icon">
|
||||
<slot wx:if="{{addContent === 'slot'}}" name="add-content" />
|
||||
<t-icon wx:else name="add" />
|
||||
</view>
|
||||
</view>
|
||||
</t-grid-item>
|
||||
</t-grid>
|
||||
</view>
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
.t-float-left {
|
||||
float: left;
|
||||
}
|
||||
.t-float-right {
|
||||
float: right;
|
||||
}
|
||||
@keyframes tdesign-fade-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.hotspot-expanded.relative {
|
||||
position: relative;
|
||||
}
|
||||
.hotspot-expanded::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
.t-upload__grid-content {
|
||||
padding: 0;
|
||||
}
|
||||
.t-upload__grid-file {
|
||||
position: relative;
|
||||
}
|
||||
.t-upload__add-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--td-upload-add-icon-font-size, 56rpx);
|
||||
background-color: var(--td-upload-add-bg-color, var(--td-gray-color-1, #f3f3f3));
|
||||
color: var(--td-upload-add-color, var(--td-font-gray-3, rgba(0, 0, 0, 0.4)));
|
||||
border-radius: var(--td-upload-radius, var(--td-radius-default, 12rpx));
|
||||
}
|
||||
.t-upload__thumbnail {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.t-upload__wrapper {
|
||||
position: relative;
|
||||
border-radius: var(--td-upload-radius, var(--td-radius-default, 12rpx));
|
||||
overflow: hidden;
|
||||
}
|
||||
.t-upload__close-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-top-right-radius: var(--td-upload-radius, var(--td-radius-default, 12rpx));
|
||||
border-bottom-left-radius: var(--td-upload-radius, var(--td-radius-default, 12rpx));
|
||||
background-color: var(--td-font-gray-3, rgba(0, 0, 0, 0.4));
|
||||
}
|
||||
.t-upload__progress-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--td-font-gray-3, rgba(0, 0, 0, 0.4));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: var(--td-upload-radius, var(--td-radius-default, 12rpx));
|
||||
color: var(--td-white-color-1, #fff);
|
||||
padding: 32rpx 0;
|
||||
}
|
||||
.t-upload__progress-text {
|
||||
font-size: 24rpx;
|
||||
line-height: 40rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
.t-upload__progress-loading {
|
||||
animation: spin infinite linear 0.6s;
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user