mpa-uploader

1.0.0 • Public • Published

MPA-UPLOAD-COMPONENTS 文件上传组件

简介

该组件负责将文件上传到云空间。整个上传文件过程,由以下 6 个阶段组成:

  1. 添加文件
  2. 计算文件的 Hash 值
  3. 初始化文件上传
  4. 文件预分块
  5. 上传文件
  6. 合并文件

名词解释:

  1. tid,即 Task ID, 用于标识任务的唯一 ID
  2. fid,即 FileId,用于标识文件的唯一 ID

上传组件提供了以下 API:

  // 添加一个上传文件任务
  addFiles(items, pid, behavior) {  }
  // 添加一个上传文件夹任务
  addFolder(item, pid, behavior) {  }
  // 移除任务
  remove(tid) {  }
  // 恢复任务
  resume(tid) {  }
  // 暂停任务
  async pause(tid) { }
  // 销毁当前组件
  destroy() { }

同时,组件在工作过程,会触发一些事件,调用方可以根据自己的需求订阅

  // 新的任务,当调用 addFiles/addFolder 方法时触发
  fileUploder.on("new-tasks", (tasks) => {});
  
  // 移除任务,当调用 remove 方法时触发
  fileUploder.on("remove-task", (tid) => { });

  // 任务的状态发生变更,status 取值:ERROR: -1, WAITING: 0, UPLOADING: 1, AUSE: 2, COMPLETE: 3,
  fileUploder.on("task-status-change", (tid, status) => { });

  // 上传文件的状态发生变更 status 取值:ERROR: -1, WAITING: 0, UPLOADING: 1, AUSE: 2, COMPLETE: 3,
  fileUploder.on("file-status-change", (tid, fid, status) => { });

  // 上传速度,其中 e :{tid:'任务ID', rate:'上传速度(单位bytes)', commit:'当前已上传多少(单位bytes)'}, 
  fileUploder.on("upload-speed", (e) => {});

  // 上传进度,其中 e :{tid:'任务ID', uploaded:'已上传字节数', total:'任务总大小'}
  fileUploder.on("upload-progress", (e) => { });

  // 开始计算文件MD5
  fileUploder.on("begin-hash", (tid, fid) => { });

  // 计算文件MD5结束
  fileUploder.on("end-hash", (tid, fid) => { });

  // 计算文件MD5进度:e = { tid: '', fid: '', fileName: '文件名', percent: 进度值[0-100] }
  fileUploder.on("hash-progress", (e) => { });
  
  // 准备初始化文件
  fileUploder.on("begin-prepare", (tid, fid) => { })

  // 初始化文件结束
  fileUploder.on("end-prepare", (tid, fid) => { });

  // 初始化文件结果 file = {metadatas: '文件元数据', md5: '文件hash值', uploadId: '上传ID', blockInfo: '分块信息'}
  fileUploder.on("prepared", (file) => { });
  
  // 准备提交分块信息
  fileUploder.on("begin-commit-blocks", (tid, fid) => {});

  // 提交分块信息结束
  fileUploder.on("end-commit-blocks", (tid, fid) => {});
  
  // 准备上传文件
  fileUploder.on("begin-upload-file", (tid, fid) => {})

  // 上传文件结束
  fileUploder.on("end-upload-file", (tid, fid) => {});

  // 开始合并文件
  fileUploder.on("begin-merge-file", (tid, fid) => {});
  
  // 合并文件结束
  fileUploder.on("end-merge-file", (tid, fid) => {});

  // 上传被取消,一般调用 pause 方法时,会触发该事件
  fileUploder.on("abort", (tid) => {});

  // 上传完成
  fileUploder.on("complete", (task) => {}); 

  // 上传出错 e = {tid, fid, code, message} 
  // code 取值:
  // OK: 0, 
  // USER_ABORT: 1, 
  // CALC_MD5_FAILED: 2, 
  // PREPARE_UPLOAD_FAILED: 3,
  // COMMIT_BLOCKS_FAILED: 4, 
  // UPLOAD_FILE_FAILED: 5, 
  // MERGE_FILE_FAILED: 6,  
  // UNKNOWN: 7,
  fileUploder.on("error", (e) => {  });

初始化组件

使用组件之前,需要现对其实例化操作,实例化需要一些必须的参数,需要提供。

import FileUploader from "./FileUploader";
// 参数
const options = {
  domain: "http://xxxx.com", // 接口域名
  debug: true, // 是否调试模式, 将打印大量信息
  headers?: {
    deviceType: "1",
    spaceId: "0583d",
    userId: "",
    token: "",
    deviceId: "",
  }, // 请求头信息,如果存在 cookies,则可以不用传递
};
// 实例化
const fileUploder = new FileUploader(options);

添加任务

你可以上传文件或者文件夹,添加完成后,系统将通过事件的方式,告知添加的结果,主要包含 2 个 API:

  1. addFiles(items, pid, behavior): 添加文件
  2. addFolder(item, pid, behavior): 添加文件夹

示例

<template>
  <input type="file" @change="handleFileUpload" multiple />
  <input type="file" @change="handleFolderUpload" webkitdirectory />
</template>
    const behavior = "RENAME" // 文件重命名行为
    const pid = "1111" // 要上传文件的上级文件夹 ID

    const fileUploder = new FileUploader(options);

    // 上传文件
    handleFileUpload(event) {
      const target = event.target;
      const files = Array.from(target.files); // 文件列表
      const ok = fileUploader.addFiles(files, pid, behavior);
      if (!ok) return;// 文件添加失败
    }

     // 上传文件夹
    handleFolderUpload(event) {
      const target = event.target;
      const files = Array.from(target.files);
      const ok = fileUploader.addFolder(files, pid, behavior);
      if (!ok) return; // 文件夹添加失败
    }

    // 添加文件后,创建了一个新任务的回调
    fileUploder.on("new-tasks", tasks => {
        // 任务列表
        // 任务对象属性组成
        // {
        //     tid: '', // 任务ID
        //     pid: '', // 上传文件的上级文件夹 ID
        //     isdir: false, // 是否是文件夹
        //     name: 'file.name', // 任务名称
        //     size: 1000, // 要上传文件(夹)的总大小 单位 byte
        //     behavior: 'RENAME', // 文件重名行为
        //     status: 0, // FileStatus 任务状态,见下列表
        // }

        // const FileStatus = {
        //     ERROR: -1, // 错误
        //     WAITING: 0, // 等待上传
        //     UPLOADING: 1, // 上传中
        //     PAUSE: 2, // 暂停中
        //     COMPLETE: 3, // 上传完成
        // };
    })

暂停任务

通过调用 pause,可以取消任务,一旦被取消,将触发 abort 和 task-status-change 事件,调用方可以根据自身逻辑处理渲染层。

pause(tid): 暂停任务

const fileUploder = new FileUploader(options);
fileUploder.on("abort", (tid) => {
  // 任务已暂停
});
fileUploder.on("task-status-change", (tid, status) => {
 // 更新页面上的任务状态
});
const tid = "929w222";
fileUploder.pause(tid);

恢复暂停或者出错的任务

通过调用 resume() 可以继续上传被暂停或者出错的任务,一旦任务开始,将触发 task-status-change 事件

const fileUploder = new FileUploader(options); 
fileUploder.on("task-status-change", (tid, status) => {
 // 更新页面上的任务状态
});
const tid = "929w222";
fileUploder.resume(tid);

删除任务

你可以通过 tid ,即 TaskId 删除任务,删除完成后,将通过事件的方式,通知你已删除完成。

remove(tid) : 删除任务

const fileUploder = new FileUploader(options);
fileUploder.on("remove-task", (tid) => {
  // 任务已删除
});
const tid = "929w222";
fileUploder.remove(tid);

上传文件

上传文件分 5 个步骤,将依次触发下面的事件(注意,不是每个事件一定都会触发)

  1. 计算文件的 Hash 值,触发事件:begin-hash、hash-progress、end-hash
  2. 文件初始化,触发事件:begin-prepare、prepared、begin-prepare
  3. 文件预分块,触发事件:begin-commit-blocks、end-commit-blocks
  4. 文件上传,触发事件:begin-upload-file、upload-speed、upload-progress、end-upload-file
  5. 合并文件,触发事件:begin-merge-file、complete、end-merge-file

示例

 const fileUploader = new FileUploader(options);
 fileUploader.on("begin-hash" (tid, fid) => {
    // 开始计算文件MD5
    // tid, TaskId, 即任务 ID,随机生成的标识
    // fid, FileId, 文件ID,随机生成的标识
 })
  fileUploader.on("end-hash" (tid, fid) => {
    // 计算文件MD5完成
 })
  fileUploader.on("hash-progress" ({ tid, fid, fileName, percent }) => {
    // 正在计算文件MD5
    // fileName 正在计算的文件名
    // percent 当前进度 1-100
 })
 fileUploader.on("complete", (task) => {
    // 文件上传完成
 })

VUE 示例

View

  <div class="hello">
    <span>文件夹</span>
    <input type="file" @change="handleFolderUpload" webkitdirectory multiple />
    <br />
    <span>文件</span>
    <input type="file" @change="handleFileUpload" multiple />
    <br />
    <table border="1">
      <tr v-for="task of tasks" :key="task.tid">
        <td>任务ID: {{ task.tid }}</td>
        <td>状态:{{ task.status }}</td>
        <td>速度:{{ speeder(task.tid) }}</td>
        <td>进度:{{ processer(task.tid) }}</td>
        <td>
          <button @click="onStartTask(task.tid)">开始</button>
          <button @click="onCancelTask(task.tid)">暂停</button>
          <button @click="onRemoveTask(task.tid)">删除</button>
        </td>
      </tr>
    </table>
  </div> 

Javascript:

import FileUploader from "mpa-upload-components";
import { bytesToSize } from "mpa-upload-components/src/utils";

const options = {
  debug: true,
  domain: "http://xxx.com",
  headers: {
    deviceType: "",
    spaceId: "",
    userId: "",
    token: "",
    deviceId: "",
  },
};

const pid = "上级目录的ID";
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },

  data() {
    return {
      fileMd5: null,
      percent: 0,
      tasks: [],
      speeds: [],
      progresses: [],
      fileUploader: null,
    };
  },

  methods: {
    async handleFolderUpload(event) {
      const target = event.target;
      const files = Array.from(target.files);
      const task = this.fileUploader.addFolder(files, pid);
    },

    async handleFileUpload(event) {
      const target = event.target;
      const files = Array.from(target.files);
      const task = this.fileUploader.addFiles(files, pid);
    },

    onStartTask(tid) {
      this.fileUploader.resume(tid);
    },

    onCancelTask(tid) {
      this.fileUploader.pause(tid);
    },

    onRemoveTask(tid) {
      this.fileUploader.remove(tid);
    },
  },

  computed: {
    speeder() {
      return (tid) => {
        const speed = this.speeds.find((t) => t.tid === tid);
        if (!speed) return "";
        return `${speed.rate}kb/s`;
      };
    },

    processer() {
      return (tid) => {
        const progress = this.progresses.find((t) => t.tid === tid);
        if (!progress) return "";
        const value = ~~((progress.uploaded / progress.total) * 100);
        return `${progress.uploaded}/${progress.total} (${value})%`;
      };
    },
  },

  created() {
    this.fileUploader = new FileUploader(options);
    this.fileUploader.on("new-tasks", (tasks) => {
      this.tasks.push(...tasks);
    });

    this.fileUploader.on("remove-task", (tid) => {
      const index = this.tasks.findIndex((task) => task.tid === tid);
      this.tasks.splice(index, 1);
    });

    this.fileUploader.on("task-status-change", (tid, status) => {
      const task = this.tasks.find((task) => task.tid === tid);
      task.status = status;
    });

    this.fileUploader.on("upload-speed", (e) => {
      const speed = this.speeds.find((t) => t.tid === e.tid);
      if (speed) {
        speed.rate = bytesToSize(e.rate);
        speed.commit = e.commit;
      } else {
        this.speeds.push(e);
      }
    });

    this.fileUploader.on("upload-progress", (e) => {
      const progress = this.progresses.find((t) => t.tid === e.tid);
      if (progress) {
        progress.total = e.total;
        progress.uploaded = e.uploaded;
      } else {
        this.progresses.push(e);
      }
    });
  },
};

Readme

Keywords

none

Package Sidebar

Install

npm i mpa-uploader

Weekly Downloads

15

Version

1.0.0

License

MIT

Unpacked Size

336 kB

Total Files

29

Last publish

Collaborators

  • webrtcn