Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ximing/uploader-x


https://github.com/ximing/uploader-x

react uploader web-upload

Last synced: 9 days ago
JSON representation

Awesome Lists containing this project

README

        

# uploader-x

## 引入方式

建议使用 ES6 引入。

```javascript
import { Uploader, FileStatus } from 'uploader-x';
```

- `Uploader`:文件传输 SDK 的构造类
- `FileStatus`:文件实例的状态
- `INITED`:初始状态(beforeFileQueued 事件之后就会变更)
- `QUEUED`:已经进入队列, 等待上传
- `PROGRESS`:上传中
- `ERROR`:上传出错,可重试
- `CANCELLED`:上传取消,会清出队列
- `INTERRUPT`:上传中断,可续传
- `INVALID`:文件不合格,不能重试上传

## 初始化

### eg.

```javascript
let uploader = new Uploader({
pick: '.ff-wrap .up-btn',
dnd: 'body, .dnd-area',
paste: ['body', '.paste-area'],
listenerContainer: document,
body: document.body,
chunked: true,
chunkSize: 20971520,
multiple: true,
withCredentials: false,
});
```

### 初始化参数

| 参数名 | 数据类型 | 默认值 | 说明 |
| :------------------ | :------- | :-------------------------------- | :------------------------------------------ |
| timeout | Number | 0 | 超时时间,为 0 时不会设置超时事件 |
| accept | Array | [] | [{extensions: 'jpg', mimeTypes: 'image/*'}] |
| auto | Boolean | true | 是否得到文件后就上传,暂不支持设置为 false |
| sameTimeUploadCount | Number | 3 | 同时上传分片的个数 |
| chunked | Boolean | false | 是否开启分片上传 |
| chunkSize | Number | 20971520 | 分片大小,默认是 20MB |
| chunkRetry | Number | 2 | 分片失败重试次数(不建议更改太大) |
| formData | Object | {} | 除了二进制文件外,拓展的 formData 对象 |
| headers | Object | {} | 自定义头 |
| fileVal | String | 'file' | formData 二进制文件的 key |
| method | String | 'post' | 请求方法 |
| fileNumLimit | Number | undefined | 暂不启用 |
| fileSizeLimit | Number | undefined | 暂不启用 |
| fileSingleSizeLimit | Number | undefined | 暂不启用 |
| dnd | String | void 0 | 拖拽区域选择器 |
| pick | String | void 0 | 点击区域的选择器 |
| pickDir | String | void 0 | 点击区域的选择器(选择文件夹) |
| paste | String | void 0 | 粘贴区域选择器 |
| server | String | '' | 服务器地址 |
| listenerContainer | DOM | document | 事件委托的 DOM 元素 |
| body | DOM | document.body | 动态创建的 input 插入到的 DOM 元素 |
| multiple | Boolean | false | 是否可以选择多文件上传 |
| withCredentials | Boolean | true | 是否开启跨域带 cookie |
| setName | Function | (id) => new Date().getTime() + id | 无文件名文件函数 |
| log | Function | console.log | 记录 log 的函数 |
| logLevel | Number | 1 | 暂时不开启使用 |

其中`pick`、`dnd`、`paste`填写选择器的时候支持 Selector String,通过`,`分隔的 Selector String,存放 Selector String 的数组。

## file 对象封装

file 对象封装在事件回调函数中返回的参数对象里为`file`的`key`

- `eventEmitter`:事件发射器
- `ext`:文件后缀
- `id`:文件唯一标识符,eg:`X_FILE_0`
- `isFile`:是否是文件(有可能是目录呢)
- `lastModifiedDate`:最后修改时间
- `loaded`:上传字节数
- `name`:文件名
- `path`:文件路径
- `uploadGroupId`:文件组 ID
- `size`:文件大小(字节数)
- `source`:原生文件对象
- `statusText`:文件状态,即`FileStatus`的值
- `type`:文件的 MIME Type,eg`video/mp4`

## 事件

所有的事件的回调函数返回的参数均是一个对象,参数中可能有的值说明

| 名称 | 数据类型 | 说明 | 存在事件 |
| :----------- | :------- | :----------------------------------------- | :------------- |
| file | Object | 即上面的 file 对象封装 | 所有事件 |
| currentShard | Number | 当前文件分片,从 1 开始计算,不是从 0 开始 | 大部分事件 |
| shardCount | Number | 文件总分片 | 大部分事件 |
| shard | Blob | 分片的二进制对象,一般很少用到 | 大部分事件 |
| total | Number | 文件的总字节数 | 大部分事件 |
| loaded | Number | 文件读取的字节数 | uploadProgress |
| isUploadEnd | Boolean | 文件是否传输完毕 | uploadProgress |
| responseText | String | 分片请求后的服务端返回 | uploadAccept |
| responseText | String | 分片请求后的服务端返回 | uploadAccept |
| error | Error | 上传错误信息 | uploadError |

- `beforeFilesSourceQueued`: 选择上传一组文件之前 包含目录源信息
`@return Object { filesSource, actionType, uploadGroupId }`
**demo**

```javascript
uploader.on('beforeFilesSourceQueued', obj => {
let { filesSource, actionType, uploadGroupId } = obj;
if (actionType === 'pickDir') {
// 选择的是文件夹
}
// 超过10个文件不允许上传
if (filesSource.length > 10) {
return false;
}
});
```

- `filesSourceQueued`: 选择上传一组文件之后 文件源信息
`@return Object { filesSource, actionType, uploadGroupId }`
**demo**

```javascript
uploader.on('filesSourceQueued', obj => {
let { filesSource, actionType, uploadGroupId } = obj;
if (actionType === 'pickDir') {
// 选择的是文件夹
}
});
```

- `beforeFileQueued`:文件添加到上传队列之前,可以对文件进行一些过滤,`return false;`会阻止将该文件加入队列。

`@return Object { file }`

**demo**

```javascript
uploader.on('beforeFileQueued', obj => {
console.log('beforeFileQueued');
let { file, setContentType } = obj;
setContentType('image/png'); // 更改文件的Content-Type

if (/^[^<>\|\*\?\/]*$/.test(file.name)) {
let b1 = new Buffer(file.name);
let bytes = Array.prototype.slice.call(b1, 0);
if (bytes.length > 128) {
alert('字符长度过长');
return false;
}
} else {
alert('存在特殊字符');
return false;
}

return true;
});
```

- `fileQueued`:没有被`beforeFileQueued`阻止,文件已经被添加进队列,等待上传。

`@return Object { file }`

**demo**

```javascript
uploader.on('fileQueued', obj => {
console.log('fileQueued');
let { file } = obj;

this.setState({
fileList: [...this.state.fileList, file],
});
});
```

- `uploadStart`:该文件已经开始上传(第一片分片已经上传了)。

`@return Object { file }`

**demo**

```javascript
uploader.on('uploadStart', obj => {
console.log('uploadStart');
let { file } = obj;

// 开始请求的文件statusText属性会有变化
let newFileList = this.state.fileList.map(fileItem =>
file.id === fileItem.id ? file : fileItem,
);
this.setState({ fileList: newFileList });
});
```

- `uploadBeforeSend`:每一个分片上传之前,可以修改`new Uploader`的时候传入的部分属性,如`server`、`headers`。

`@return Object { file, currentShard[Number], shardCount[Number], shard[Blob] }`

**demo**

```javascript
uploader.on('uploadBeforeSend', obj => {
console.log('uploadBeforeSend');
let { file, currentShard, shard, shardCount, config } = obj;

config.headers = {
name: file.name,
path: '/person/img',
};
config.server = 'http://xxx.com/file/upload';
});
```

- `uploadProgress`:上传进度回调。

`@return Object { file, loaded[Number], total[Number], shardLoaded[Number], shardTotal[Number] }`

其中`loaded`和`total`是整体文件的,`shardLoaded`和`shardTotal`是单个分片的,`file.loaded`已经是`loaded`的值。

**demo**

```javascript
uploader.on('uploadProgress', obj => {
console.log('uploadProgress');
let { file, loaded, total, shardLoaded, shardTotal } = obj;

console.log((loaded / total) * 100 + '%', file.loaded);
this.setState({
fileList: this.state.fileList.map(item =>
item.id === file.id ? file : item,
),
});
});
```

- `fileMd5Finished`:上传进度回调。

`@return Object { file, md5 }`

**demo**

```javascript
uploader.on('fileMd5Finished', async obj => {
let { file, md5 } = obj;
let res = await api.md5Check(md5);
if (res.ok === true) {
file.url = res.url;
file.loaded = file.size;
file.statusText = FileStatus.COMPLETE;
render(file); // 渲染文件
return Uploader.CONSTANTS.MD5_HAS;
}
});
```

- `uploadAccept`:分片上传成功。

`@return Object { file, shard[Blob], shardCount[Number], currentShard[Number], isUploadEnd[Boolean], responseText[String] }`

**demo**

```javascript
uploader.on('uploadAccept', async obj => {
console.log('uploadAccept');
let {
file,
shard,
shardCount,
currentShard,
isUploadEnd,
responseText,
} = obj;
});
```

* `uploadSuccess`:文件上传成功。

`@return Object { file, currentShard[Number], shardCount[Number], shard[Blob], responseText[String], responseTextArr[Array] }`

**demo**

```javascript
uploader.on('uploadSuccess', obj => {
console.log('uploadSuccess');
let {
file,
currendShard,
shardCount,
shard,
responseText,
responseTextArr,
} = obj;

if (shardCount === 1) {
t;
} else {
// use responseTextArr
}

let newFileList = this.state.fileList.map(item =>
file.id === item.id ? file : item,
);
this.setState({ fileList: newFileList });
});
```

* `uploadEndSend`:文件上传结束,成功失败都会触发。

同`uploadSuccess`

* `uploadError`:文件上传失败。

`@return Object { file, error[Error] }`

文件夹相关的事件:

- `beforeChildFileQueued`:文件夹中的子文件入队列之前
`@return Object { fileSource, parentEntry, uploadGroupId, actionType }`

- `childFileQueued`:文件夹中的子文件入队列之后
`@return Object { fileSource, parentEntry, uploadGroupId, actionType }`

- `beforeChildDirQueued`:文件夹中的子文件夹入队列之前
`@return Object { currentEntry, parentEntry, uploadGroupId, actionType }`

- `childDirQueued`:文件夹中的子文件夹入队列之后
`@return Object { currentEntry, parentEntry, uploadGroupId, actionType }`

- `selectDir`:选择了文件夹,参数返回 entry 信息,通过 return false; 可以禁止
`@return Object { entry, uploadGroupId, actionType }`