封装一个文件切片上传——上传进度计算

一、需求

可实现文件上传,包括但不限于图片、文档、视频、音频等类型,当然具体类型的支持依赖于服务端接口的实现,并且约定好参数。

前端要做的就是:

  • 文件切片
  • 发送上传请求给服务端
  • 上传进度计算

服务端要做的就是:

  • 类型检查
  • 接收切片
  • 合并所有切片

二、具体实现

1、类型文件mimeType.js

先导出一个类型文件,后面会用到。

// mimeType.js
export default {
    //视频类
    'avi': 'video/x-msvideo',
    'dv': 'video/x-dv',
    'mp4': 'video/mp4',
    'mpeg': 'video/mpeg',
    'mpg': 'video/mpeg',
    'mov': 'video/quicktime',
    'wm': 'video/x-ms-wmv',
    'flv': 'video/x-flv',
    'mkv': 'video/x-matroska',
    'rmvb': 'video/vnd.rn-realmedia-vbr',
    'wmv': 'video/x-ms-wmv',
    'vob': 'video/x-ms-vob',
    //音频类
    'mp3': 'audio/mpeg',
    'mid': 'audio/midi',
    'ogg':  'audio/ogg',
    'mp4a': 'audio/mp4',
    'wav': 'audio/wav',
    'wma': 'audio/x-ms-wma',
    'ape': 'audio/ape',
    'flac': 'audio/flac',
    'aac': 'audio/aac'
}

2、文件切片

定义默认切片大小 chunkSize = 2 * 1024 * 1024
文件分割使用文件对象 File 的方法 File.prototype.slice

代码实现:

// 导入上面的mimeType文件
import mimeType from './mimeType';

_slice() {
    let totalSize = this.file.size;
    let start = 0;
    let end = start + this.chunkSize;
    let chunks = [];
    let mimetype = 'text/pdf';   // 默认文件类型
    if (this.file.type.includes('video') || this.file.type.includes('audio')) {
        mimetype = this.file.type
    }
    // rmvb文件类型需要处理
    if (this.file.name.endsWith('rmvb') || this.file.name.endsWith('RMVB')) {
        mimetype = mimeType['rmvb']
    }
    // this.file.type不存在时,使用文件后缀名
    if (!this.file.type) {
        let arr = this.file.name.split('.');
        let ext = arr[arr.length - 1].toLowerCase();
        if (/(avi|dv|mp4|mpeg|mpg|mov|wm|vob|flv|mkv|rmvb|wmv|mp3|mid|ogg|mp4a|wav|wma|ape|flac|aac)/.test(ext)) {
            mimetype = mimeType[ext];
        }
    }
    while (start < totalSize) {
        // 根据长度截取每次需要上传的数据
        let chunk = this.file.slice(start, end, mimetype);
        chunks.push(chunk);
        start = end;
        end = start + this.chunkSize;
    }
    return chunks
}

以上返回切片后的文件。

3、发送请求到服务端

使用 axios,一个基于promise的网络请求库,作用于node.js和浏览器中。
根据约定好的请求参数,组织数据 FormData

代码实现

import axios from 'axios';

_sendRequest(chunkIndex, chunk, params) {
    let formData = new FormData();
    // TODO 根据和服务端同学约定的接口组织请求参数
    formData.append('file', chunk, this.file.name);   // 切片后的文件
    formData.append('dname', this.file.name);   // 文件名
    formData.append('dzchunkindex', chunkIndex);   // 切片索引
    formData.append('dztotalchunkcount', this.chunks.length);   // 所有切片长度
    formData.append('dztotalfilesize', this.file.size);   // 切片大小

    if (params && typeof params === 'object') {
        for (let k in params) {
            formData.append(k, params[k]);
        }
    }
    return axios({
        method: this.method,
        baseURL: this.baseURL,
        url: this.url,
        data: formData,
    }).then(res => {
        return res.data
    }).catch(err => {
        return err;
    });
}

在以上代码中,在上传切片的同时,也会告诉后端当前上传切片的 chunkIndex,后端接收后,记录该 chunkIndex 以便在合并时知道切片的顺序。

4、上传处理(上传进度&成功/失败)

  • onStart 上传开始回调
  • onSuccess 上传成功回调
  • onError 上传失败回调
  • onProgress 上传进度回调
  • onCancel 上传取消回调
async upload(params) {
	// 上传开始的回调
    this.onStart && this.onStart();
    for (let i = 0; i < this.chunks.length; i++) {
        if (this.cancelled) {
        	// 上传取消处理
            this.onCancel && this.onCancel();
            break;
        }
        console.log(`---------发送文件${this.file.name}${i + 1}个切片-------`);
        let res = await this._sendRequest(i, this.chunks[i], params);
        if (res.success === 1) {
        	// TODO 约定的上传成功的返回参数
            console.log(`---------发送文件${this.file.name}${i + 1}个切片成功-------`);
            // 上传进度计算
            this.onProgress && this.onProgress((((i + 1) / this.chunks.length) * 100).toFixed(1));
            if (i === this.chunks.length - 1) {
            	// 切片是最后一片,上传成功处理
                this.onSuccess && this.onSuccess(res);
                break;
            }
        } else {
			// 上传失败处理
            this.onError && this.onError();
            break;
        }
    }
}

当所有切片上传完成(即 当前切片索引 = 所有切片长度-1 )后,不再发送上传请求,即通知后端把所有切片进行合并,最终完成整个上传流程。
这样,一个基本的文件切片上传就实现了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值