vue-simple-uploader 是一个基于 Vue.js 的简单文件上传插件,可支持文件分片上传、断点续传以及秒传,有以下几个特点:

1、简单易用:只需在 Vue 组件中使用该插件,并设置相应的配置选项即可实现文件上传功能。

2、多文件上传:插件支持同时上传多个文件,可以选择并一次性上传多个文件。

3、进度条显示:该插件提供了进度条显示上传进度,让用户清楚地知道文件上传的状态和进度。

4、上传前验证:可以通过设置验证规则,对上传的文件进行前端验证。例如,限制文件类型、大小等,以确保只上传符合要求的文件。

5、自定义选项:插件提供了一些可自定义的选项,如上传地址、请求头部、参数等,以满足不同的业务需求。

6、事件回调:提供了丰富的事件回调函数,允许在不同的上传阶段执行自定义逻辑,如上传前、上传成功、上传失败等。

总之,Vue Simple Uploader 简化了文件上传的过程,并提供了一些有用的功能和灵活的配置选项,易于集成和使用。

最终成功效果

1、首先需要下载依赖,vue-simple-uploader、spark-md5

npm i --save vue-simple-uploader@next spark-md5

下载好的版本号是1.0.1,这个版本是支持vue3的,不加@next 默认是0.7.6,是只支持vue2的,vue3中使用会报错。

2、main.js 注册
import { createApp } from 'vue';
import App from './App.vue';
// 文件分片上传
import uploader from 'vue-simple-uploader';
import 'vue-simple-uploader/dist/style.css';

createApp(App).use(uploader).mount('#app');
3、编写文件类型 accept.config.js
export const ACCEPT_CONFIG = {
	image: ['.png', '.jpg', '.jpeg', '.gif', '.bmp'],
	video: ['.mp4', '.rmvb', '.mkv', '.wmv', '.flv'],
	document: [
		'.doc',
		'.docx',
		'.xls',
		'.xlsx',
		'.ppt',
		'.pptx',
		'.pdf',
		'.txt',
		'.tif',
		'.tiff',
		'.rar',
		'.zip',
	],
	getAll() {
		return [...this.image, ...this.video, ...this.document];
	},
};
4、编写upload.vue
<template>
	<div>
		<!-- 上传器 -->
		<uploader
			ref="uploaderRef"
			:options="options"
			:autoStart="false"
			:file-status-text="fileStatusText"
			class="uploader-ui"
			@file-added="onFileAdded"
			@file-success="onFileSuccess"
			@file-progress="onFileProgress"
			@file-error="onFileError"
		>
			<uploader-unsupport></uploader-unsupport>
			<uploader-drop>
				<div>
					<uploader-btn id="global-uploader-btn" ref="uploadBtn" :attrs="attrs"
						>选择文件<i class="el-icon-upload el-icon--right"></i
					></uploader-btn>
				</div>
			</uploader-drop>
			<uploader-list></uploader-list>
		</uploader>
	</div>
</template>

<script setup>
import { ACCEPT_CONFIG } from '@/config/accept.config';
import { reactive, ref } from 'vue';
import SparkMD5 from 'spark-md5';
import { mergeFile } from '@/api/demo/fileUpload/index';
import { ElMessage } from 'element-plus';

const options = reactive({
	//目标上传 URL,默认POST, import.meta.env.VITE_API_URL = api
    // target ==》http://localhost:6666/api/uploader/chunk
	target: import.meta.env.VITE_API_URL + '/uploader/chunk',
	query: {},
	headers: {
        // 需要携带token信息,当然看各项目情况具体定义
		token: "your_token",
	},
	//分块大小(单位:字节)
	chunkSize: '2048000',
	//上传文件时文件内容的参数名,对应chunk里的Multipart对象名,默认对象名为file
	fileParameterName: 'upfile',
	//失败后最多自动重试上传次数
	maxChunkRetries: 3,
	//是否开启服务器分片校验,对应GET类型同名的target URL
	testChunks: true,
	// 服务器分片校验函数
	checkChunkUploadedByResponse: function (chunk, response_msg) {
		let objMessage = JSON.parse(response_msg);
		console.log(response_msg, 'response_msg');
		if (objMessage.skipUpload) {
			return true;
		}
		return (objMessage.uploadedChunks || []).indexOf(chunk.offset + 1) >= 0;
	},
});
const attrs = reactive({
	accept: ACCEPT_CONFIG.getAll(),
});
const fileStatusText = reactive({
	success: '上传成功',
	error: '上传失败',
	uploading: '上传中',
	paused: '暂停',
	waiting: '等待上传',
});
onMounted(() => {
	console.log(uploaderRef.value, 'uploaderRef.value');
});
function onFileAdded(file) {
	computeMD5(file);
}

function onFileSuccess(rootFile, file, response, chunk) {
	//refProjectId为预留字段,可关联附件所属目标,例如所属档案,所属工程等
	file.refProjectId = '123456789';
	mergeFile(file)
		.then((responseData) => {
			if (responseData.data.code === 415) {
				console.log('合并操作未成功,结果码:' + responseData.data.code);
			}
			ElMessage.success(responseData.data);
		})
		.catch(function (error) {
			console.log('合并后捕获的未知异常:' + error);
		});
}
function onFileError(rootFile, file, response, chunk) {
	console.log('上传完成后异常信息:' + response);
}

/**
 * 计算md5,实现断点续传及秒传
 * @param file
 */
function computeMD5(file) {
	file.pause();

	//单个文件的大小限制2G
	let fileSizeLimit = 2 * 1024 * 1024 * 1024;
	console.log('文件大小:' + file.size);
	console.log('限制大小:' + fileSizeLimit);
	if (file.size > fileSizeLimit) {
		file.cancel();
	}

	let fileReader = new FileReader();
	let time = new Date().getTime();
	let blobSlice =
		File.prototype.slice ||
		File.prototype.mozSlice ||
		File.prototype.webkitSlice;
	let currentChunk = 0;
	const chunkSize = 10 * 1024 * 1000;
	let chunks = Math.ceil(file.size / chunkSize);
	let spark = new SparkMD5.ArrayBuffer();
	//由于计算整个文件的Md5太慢,因此采用只计算第1块文件的md5的方式
	let chunkNumberMD5 = 1;

	loadNext();

	fileReader.onload = (e) => {
		spark.append(e.target.result);

		if (currentChunk < chunkNumberMD5) {
			loadNext();
		} else {
			let md5 = spark.end();
			file.uniqueIdentifier = md5;
			file.resume();
			console.log(
				`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
					file.size
				} 用时:${new Date().getTime() - time} ms`
			);
		}
	};

	fileReader.onerror = function () {
		error(`文件${file.name}读取出错,请检查该文件`);
		file.cancel();
	};

	function loadNext() {
		let start = currentChunk * chunkSize;
		let end = start + chunkSize >= file.size ? file.size : start + chunkSize;

		fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
		currentChunk++;
		console.log('计算第' + currentChunk + '块');
	}
}
const uploaderRef = ref();
function close() {
	uploaderRef.value.cancel();
}
function error(msg) {
	console.log(msg, 'msg');
}
</script>

<style scoped>
.uploader-ui {
	padding: 15px;
	margin: 40px auto 0;
	font-size: 12px;
	font-family: Microsoft YaHei;
	box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-ui .uploader-btn {
	margin-right: 4px;
	font-size: 12px;
	border-radius: 3px;
	color: #fff;
	background-color: #409eff;
	border-color: #409eff;
	display: inline-block;
	line-height: 1;
	white-space: nowrap;
}
.uploader-ui .uploader-list {
	max-height: 440px;
	overflow: auto;
	overflow-x: hidden;
	overflow-y: auto;
}
</style>
5、这是最后合并需要的接口 mergeFile,这个看各项目是怎么封装request,下面只是个例子
import request from '@/utils/request';

export const mergeFile = (data) => {
	return request({
		url: '/uploader/mergeFile',
		method: 'POST',
		data,
	});
};
6、使用
<template>
	<div>
		<UploadVue />
	</div>
</template>
<script setup>
import UploadVue from './Upload.vue';
</script>

上传文件后端一共需要写三个接口,其中给到前端只需要两个即可,如下:

1、/uploader/chunk:upload.vue文件的options对象下的target,这里需要注意接口携带token的问题,也有些项目是cookie,还有就是跨域的问题,也就是为什么要用import.meta.env.VITE_API_URL进行拼接的原因,本地联调的话因为VITE_APP_URL环境变量设置的是 /api ,所以是http://localhost:6666/api/uploader/chunk

2、/uploader/mergeFile:这个是将上传文件成功后的各分片最后合并的接口

Logo

前往低代码交流专区

更多推荐