enlarge-file-upload
v1.0.33
Published
A tool for chunked file upload with concurrency control.
Downloads
85
Maintainers
Readme
File Upload Tool
请优先下载最新版本库 这是一个用于大文件上传的工具包,提供了系列函数用来支持暂停、恢复、上传进度等功能,内置了错误重传策略,支持断点续传、重传、重试等功能(此库上传基于 axios 库,如果项目不支持 axios,勿用...)。 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.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></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。