2.0.35 • Published 5 months ago

enlarge-file-upload v2.0.35

Weekly downloads
-
License
ISC
Repository
github
Last release
5 months ago

File Upload Tool

请优先下载最新版本库 这是一个用于大文件上传的工具包,提供了系列函数用来支持暂停、恢复、上传进度等功能,内置了错误重传策略,支持断点续传、重传、重试等功能(此库上传基于 axios 库,如果项目不支持 axios,勿用...)。 线上演示地址:http://jiang-12-13.com:8988/ 仅用于本库大文件上传案例在线演示,严禁上传违法内容和做其它用处。请善待服务器 QQ 讨论群:324710217

安装

npm install enlarge-file-upload

参数介绍

/**
 * 本库计算文件hash值,使用的是 crypto-js 依赖包进行计算,版本为 4.0.0 版
 * 链接:https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js
 */

/**
 * descript 入参详解
 * @param {Number} chunkSize? 文件单个切片大小,默认5MB
 * @param {Number} concurrency? 并发上传数量,默认5
 * @param {Number} maxRetries? 失败重试次数,默认3
 * @param {Number} startOffset? 断点续传偏移量,默认0
 * @param {Array} includeChunks? 需要上传的切片索引,默认上传所有切片
 * 如果startOffset和includeChunks参数同时存在,且startOffset不为0,默认优先使用startOffset参数
 * @param {Boolen} hash? 是否开启hash计算,默认不开启,可选参数
 * @param {Boolen} awaitHash? 是否等待hash值,默认等待,可选参数(仅在hash为true时生效)
 * awaitHash参数,如果上传文件较小时可以开启等待;如果文件超大,建议关闭,大文件hash值计算时间较长,避免等待阻塞主线程
 * @param {Function} uploadFunction 上传函数,必传参数
 * @param {Function} onProgress? 上传进度回调函数,可选
 * @param {Function} onSpeed? 上传速度回调函数,可选
 * @param {Function} onSuccess? 上传成功后回调函数,可选
 * @param {Function} beginHash? 开始计算Hash值回调函数,可选(只会在上传前调用一次,且hash.open必须true)
 * @param {Function} endHash? Hash值计算完毕回调函数,可选(只会在上传前调用一次,且hash.open必须true)
 */
// 参数示例
const config = {
  chunkSize: 5 * 1024 * 1024,
  concurrency: 5,
  maxRetries: 3,
  startOffset:0,
  includeChunks,
  hash: false,
  awaitHash: false,
  uploadFunction,
  onProgress,
  onSuccess
  onSpeed,
  beginHash,
  endHash
};

/**
 * descript fileUploadTool方法返回一个对象,包含上传方法、暂停方法、继续方法等
 * upload 上传方法
 * pause 暂停方法
 * resume 继续方法
 * state 状态对象,包含上传进度、hash值、上传速度等(具体请看对应的TS属性State)
 */
// 方法调用
const { upload, pause, resume, state } = fileUploadTool(config);

案例

注意:下面在 vue3 和 React 中所展示的案例,均用的是 TS 语法进行演示,但他同样适用于非 TS 语法项目,你只需自行删除案例中的 TS 类型声明即可

原生 js 中使用示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>文件上传</title>
  </head>
  <script src="https://cdn.jsdelivr.net/npm/enlarge-file-upload/dist/upload.min.js"></script>
  <!-- 引入 Axios 库,用于发送 HTTP 请求 -->
  <script src="https://cdn.jsdelivr.net/npm/axios"></script>

  <body>
    <input type="file" id="fileInput" />
    <button id="pauseButton">暂停上传</button>
    <button id="resumeButton">继续上传</button>
    <div id="progress">上传进度:0%</div>
    <div id="speed">上传速度:0 MB/s</div>
    <script>
      // 定义上传函数
      async function uploadFunction({ chunk, index, hash, cancelToken }) {
        const formData = new FormData();
        formData.append("chunk", chunk);
        formData.append("hash", hash);
        formData.append("index", index);
        await axios.post("http://localhost:3000/api/users", formData, {
          cancelToken,
        });
      }

      // 使用示例
      const config = {
        chunkSize: 5 * 1024 * 1024, // 5MB
        concurrency: 5,
        maxRetries: 3,
        // startOffset: 6, // 从索引为10的切片位置开始传
        // includeChunks:[1,6], // 只上传索引为1和6的切片,只有startOffset为0或空时才生效
        uploadFunction,
        onProgress: (progress) => {
          document.getElementById(
            "progress"
          ).innerText = `上传进度:${state.progress.toFixed(2)}%`;
        },
        onSuccess: () => {
          console.log("上传完毕");
        },
        onSpeed: (speed) => {
          document.getElementById("speed").innerText = `上传速度:${speed}`;
        },
      };

      const { upload, pause, resume, state } = createUploader(config);
      const fileInput = document.getElementById("fileInput");
      fileInput.addEventListener("change", () => {
        const file = fileInput.files[0];
        upload(file);
      });
      // 暂停上传
      document.getElementById("pauseButton").addEventListener("click", () => {
        pause();
      });
      // 继续上传
      document.getElementById("resumeButton").addEventListener("click", () => {
        resume();
      });
    </script>
  </body>
</html>

Vue 中使用示例

在 vue3 中使用

<template>
  <div>
    <input type="file" @change="handleFileChange" />
    <button @click="handlePause">暂停上传</button>
    <button @click="handleResume">继续上传</button>
    <div>上传进度:{{ progress.toFixed(2) }}%</div>
    <div>上传速度:{{ speed }}</div>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed } from "vue";
import createUploader from "enlarge-file-upload";
import type { Config, UploadOptions } from "enlarge-file-upload"; // TS导入类型
import axios from "axios";

const progress = ref<number>(0);
const speed = ref<string>("0 MB/s");

// 定义上传函数
async function uploadFunction({
  chunk,
  index,
  hash,
  cancelToken,
}: UploadOptions): Promise<void> {
  const formData = new FormData();
  formData.append("chunk", chunk);
  formData.append("hash", hash);
  formData.append("index", index.toString());
  await axios.post("http://localhost:3000/api/users", formData, {
    cancelToken,
  });
}

// 使用 computed 来生成 uploader 配置,类型为 Config
const uploaderConfig = computed<Config>(() => ({
  chunkSize: 0.01 * 1024 * 1024, // 5MB
  concurrency: 5,
  maxRetries: 3,
  uploadFunction,
  onProgress: (progressValue: number) => {
    progress.value = progressValue;
  },
  onSuccess: () => {
    console.log("上传完毕");
  },
  onSpeed: (speedValue: string) => {
    speed.value = speedValue;
  },
}));

const uploader = ref<ReturnType<typeof createUploader> | null>(null);
uploader.value = createUploader(uploaderConfig.value);

const handleFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  if (file) {
    uploader.value?.upload(file);
  }
};

const handlePause = () => {
  uploader.value?.pause();
};

const handleResume = () => {
  uploader.value?.resume();
};
</script>

<style scoped></style>

在 vue2 中使用

<template>
  <div>
    <input type="file" @change="handleFileChange" />
    <button @click="handlePause">暂停上传</button>
    <button @click="handleResume">继续上传</button>
    <div>上传进度:{{ progress.toFixed(2) }}%</div>
    <div>上传速度:{{ speed }}</div>
  </div>
</template>

<script>
import Vue from "vue";
import createUploader from "enlarge-file-upload";
import axios from "axios";

export default Vue.extend({
  data() {
    return {
      progress: 0, // 进度
      speed: "0 MB/s", // 速度
      uploader: null, // 上传器实例
    };
  },
  methods: {
    // 定义上传函数
    async uploadFunction({ chunk, index, hash, cancelToken }) {
      const formData = new FormData();
      formData.append("chunk", chunk);
      formData.append("hash", hash);
      formData.append("index", index.toString());
      await axios.post("http://localhost:3000/api/users", formData, {
        cancelToken,
      });
    },

    // 文件选择处理
    handleFileChange(event) {
      const file = event.target.files?.[0];
      if (file && this.uploader) {
        this.uploader.upload(file);
      }
    },

    // 暂停上传
    handlePause() {
      if (this.uploader) {
        this.uploader.pause();
      }
    },

    // 继续上传
    handleResume() {
      if (this.uploader) {
        this.uploader.resume();
      }
    },
  },
  created() {
    const uploaderConfig = {
      chunkSize: 5 * 1024 * 1024, // 5MB
      concurrency: 5,
      maxRetries: 3,
      uploadFunction: this.uploadFunction,
      onProgress: (progressValue) => {
        this.progress = progressValue;
      },
      onSuccess: () => {
        console.log("上传完毕");
      },
      onSpeed: (speedValue) => {
        this.speed = speedValue;
      },
    };

    // 创建上传器实例
    this.uploader = createUploader(uploaderConfig);
  },
});
</script>

<style scoped></style>

React 中使用示例

在 react 中,这里的 useMemo 是必须要使用的,避免组件渲染的时候,重新创建 uploader 对象

import React, { useState, useMemo } from "react";
import createUploader from "enlarge-file-upload";
import type { Config, UploadOptions } from "enlarge-file-upload";
import axios from "axios";

const FileUpload = () => {
  const [progress, setProgress] = useState(0);
  const [speed, setSpeed] = useState("0 MB/s");

  // 定义上传函数
  async function uploadFunction({
    chunk,
    index,
    hash,
    cancelToken,
  }: UploadOptions) {
    const formData = new FormData();
    formData.append("chunk", chunk);
    formData.append("hash", hash);
    formData.append("index", index);
    await axios.post("http://localhost:3000/api/users", formData, {
      cancelToken,
    });
  }

  const uploaderConfig: Config = useMemo(
    () => ({
      chunkSize: 5 * 1024 * 1024, // 5MB
      concurrency: 5,
      maxRetries: 3,
      // startOffset: 6, // 从索引为10的切片位置开始传
      // includeChunks:[1,6], // 只上传索引为1和6的切片,只有startOffset为0或空时才生效
      uploadFunction,
      onProgress: (progress) => {
        setProgress(progress);
      },
      onSuccess: () => {
        console.log("上传完毕");
      },
      onSpeed: (speed) => {
        setSpeed(speed);
      },
    }),
    []
  );

  const uploader = useMemo(
    () => createUploader(uploaderConfig),
    [uploaderConfig]
  );

  const handleFileChange = (event) => {
    const file = event.target.files[0];
    uploader?.upload(file);
  };

  const handlePause = () => {
    uploader?.pause();
  };

  const handleResume = () => {
    uploader?.resume();
  };

  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      <button onClick={handlePause}>暂停上传</button>
      <button onClick={handleResume}>继续上传</button>
      <div>上传进度:{progress.toFixed(2)}%</div>
      <div>上传速度:{speed}</div>
    </div>
  );
};

export default FileUpload;

封装为 react Hooks

一个简单的封装,如有特殊需求,可以基于这个 hooks 进行二次修改

import { useState, useMemo, useCallback } from "react";
import createUploader from "enlarge-file-upload";
import type { Config, UploadOptions } from "enlarge-file-upload";
import axios from "axios";

const useFileUploader = () => {
  const [progress, setProgress] = useState(0);
  const [speed, setSpeed] = useState("0 MB/s");

  const uploadFunction = useCallback(
    async ({ chunk, index, hash, cancelToken }: UploadOptions) => {
      const formData = new FormData();
      formData.append("chunk", chunk);
      formData.append("hash", hash);
      formData.append("index", index);
      await axios.post("http://localhost:3000/api/users", formData, {
        cancelToken,
      });
    },
    []
  );

  const uploaderConfig: Config = useMemo(
    () => ({
      chunkSize: 5 * 1024 * 1024, // 5MB
      concurrency: 5,
      maxRetries: 3,
      // startOffset: 6, // 从索引为10的切片位置开始传
      // includeChunks:[1,6], // 只上传索引为1和6的切片,只有startOffset为0或空时才生效
      uploadFunction,
      onProgress: (progress) => {
        setProgress(progress);
      },
      onSuccess: () => {
        console.log("Upload complete");
      },
      onSpeed: (speed) => {
        setSpeed(speed);
      },
    }),
    [uploadFunction]
  );

  const uploader = useMemo(
    () => createUploader(uploaderConfig),
    [uploaderConfig]
  );

  const uploadFile = useCallback(
    (file) => {
      uploader?.upload(file);
    },
    [uploader]
  );

  const pauseUpload = useCallback(() => {
    uploader?.pause();
  }, [uploader]);

  const resumeUpload = useCallback(() => {
    uploader?.resume();
  }, [uploader]);

  return {
    progress,
    speed,
    uploadFile,
    pauseUpload,
    resumeUpload,
  };
};

export default useFileUploader;

使用封装好的 Hooks 示例

import React from "react";
import useFileUploader from "./useFileUploader.tsx";

const FileUpload = () => {
  const { progress, speed, uploadFile, pauseUpload, resumeUpload } =
    useFileUploader();

  const handleFileChange = (event) => {
    const file = event.target.files[0];
    uploadFile(file);
  };

  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      <button onClick={pauseUpload}>Pause Upload</button>
      <button onClick={resumeUpload}>Resume Upload</button>
      <div>Upload Progress: {progress.toFixed(2)}%</div>
      <div>Upload Speed: {speed}</div>
    </div>
  );
};

export default FileUpload;

建议

如果对此工具包有更好的建议或需要支持新的功能,欢迎提 issue 或者加本人的 QQ:1844119859。

2.0.35

5 months ago

2.0.34

5 months ago

1.0.29

9 months ago

1.0.33

9 months ago

1.0.32

9 months ago

1.0.31

9 months ago

1.0.30

9 months ago

1.0.28

12 months ago

1.0.27

12 months ago

1.0.26

12 months ago

1.0.25

12 months ago

1.0.24

1 year ago

1.0.23

1 year ago

1.0.22

1 year ago

1.0.21

1 year ago

1.0.20

1 year ago

1.0.19

1 year ago

1.0.18

1 year ago

1.0.17

1 year ago

1.0.16

1 year ago

1.0.15

1 year ago

1.0.14

1 year ago

1.0.13

1 year ago

1.0.12

1 year ago

1.0.11

1 year ago

1.0.10

1 year ago

1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago