一、概述
vue-simple-uploader中只有5种状态,分别是waiting(等待)、paused(暂停)、uploading(上传中)、success(上传成功)、error(上传失败),在进行实现断点续传及秒传时,假如要进行文件md5计算,此时的状态实际上是暂停状态,计算md5时,显示状态的文本是"暂停",我需要在计算md5时,显示状态的文本是"计算MD5",这需要在waiting状态和paused状态之间新增一个计算md5的状态,比如cmd5(计算MD5),这就需要修改vue-simple-uploader的源码来实现。
vue-simple-uploader下载地址:https://gitee.com/tojinhai/vue-uploader.git
我这里下载的是vue-simple-uploader-v1.0.1
二、魔改vue-simple-uploader
2.1 uploader.vue中新增cmd5状态
fileStatusText: {
type: [Object, Function],
default () {
return {
success: 'success',
error: 'error',
uploading: 'uploading',
paused: 'paused',
waiting: 'waiting',
cmd5:'cmd5'
}
}
},
2.2 file.vue中新增cmd5状态
- slot中新增cmd5属性
<slot
:file="file"
:list="list"
:status="status"
:paused="paused"
:error="error"
:response="response"
:average-speed="averageSpeed"
:formated-average-speed="formatedAverageSpeed"
:current-speed="currentSpeed"
:is-complete="isComplete"
:is-uploading="isUploading"
:size="size"
:cmd5="cmd5" //增加cmd5属性
:formated-size="formatedSize"
:uploaded-size="uploadedSize"
:progress="progress"
:progress-style="progressStyle"
:progressing-class="progressingClass"
:time-remaining="timeRemaining"
:formated-time-remaining="formatedTimeRemaining"
:type="type"
:extension="extension"
:file-category="fileCategory"
>
...
- 初始化cmd5值
setup (props) {
const cmd5=ref(false)
...
}
- 计算status属性的函数中添加cmd5状态
const status = computed(() => {
let isError = error
if (isComplete.value) {
return 'success'
} else if (isError.value) {
return 'error'
} else if (isUploading.value) {
return 'uploading'
} else if (cmd5.value) {//需要增加在paused前面
return 'cmd5'
} else if (paused.value) {
return 'paused'
} else {
return 'waiting'
}
})
- actionCheck中增加cmd5
const actionCheck = () => {
paused.value = props.file.paused;
error.value = props.file.error;
isUploading.value = props.file.isUploading();
cmd5.value=props.file.cmd5;
};
- onMount中增加cmd5
onMounted(() => {
paused.value = props.file["paused"];
cmd5.value = props.file["cmd5"];
...
- 最后的return中增加cmd5
return {
response,
paused,
error,
cmd5,
...
三、打包
3.1 安装依赖
运行npm install
报错
PS E:\work\vue\vue\vue-uploader-v1.0.1> npm install
npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: url-loader@0.5.9
npm error Found: webpack@3.12.0
npm error node_modules/webpack
npm error peer webpack@"2 || 3" from babel-loader@7.1.2
npm error node_modules/babel-loader
npm error dev babel-loader@"^7.1.1" from the root project
npm error peer webpack@"1 || ^2 || ^2.1.0-beta || ^2.2.0-rc || ^3" from html-webpack-plugin@2.30.1
npm error node_modules/html-webpack-plugin
npm error dev html-webpack-plugin@"^2.28.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer file-loader@"*" from url-loader@0.5.9
npm error node_modules/url-loader
npm error dev url-loader@"^0.5.8" from the root project
npm error
npm error Conflicting peer dependency: webpack@5.95.0
npm error node_modules/webpack
npm error peer webpack@"^4.0.0 || ^5.0.0" from file-loader@6.2.0
npm error node_modules/file-loader
npm error peer file-loader@"*" from url-loader@0.5.9
npm error node_modules/url-loader
npm error dev url-loader@"^0.5.8" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
执行解决
npm install --force
3.2 打包
npm run build
打包成功后会在vue-simple-uploader/dist
下生成三个文件
style.css
vue-simple-uploader.es.js
vue-simple-uploader.umd.js
四、应用
4.1 替换其他项目中依赖vue-simple-uploader下的dist文件
将打包后的文件替换到node_modules/vue-simple-uploader/dist下
4.2 删除缓存
如果项目是vite打包的,需要删除node_modules/.vite
目录,然后执行npm run dev
运行项目
4.3 项目中应用cmd5
- 状态文本提示中新增cmd5
const statusTextMap = reactive({
success: "上传成功",
error: "上传失败",
uploading: "上传中",
paused: "暂停",
waiting: "等待上传",
cmd5: "计算MD5",//新增的cmd5状态
});
- 计算md5时设置
file.cmd5=true
,计算完成后设置file.cmd5=false
/**
* 计算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();
ElMessage.error("限制上传文件大小不能超过2G");
return;
}
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;
file.cmd5 = true; //文件状态为“计算md5...”
loadNext();
fileReader.onload = (e) => {
spark.append(e.target.result);
if (currentChunk < chunks) {
loadNext();
} else {
let md5 = spark.end();
file.uniqueIdentifier = md5;
file.cmd5 = false; //取消计算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 + "块");
}
}
但是现在又出现一个问题,上传进度计算有问题,如图
查看vue-simple-uploader
源码,发现是加入cmd5状态后,计算进度有问题,使用一个变量来替换进度即可,然后重新打包替换文件就行。
# file.vue
const progressStyle = computed(() => {
let progressValue = Math.floor(progress.value * 100);
//progress.value = Math.floor(progress.value * 100);
//const style = `translateX(${Math.floor(progress.value - 100)}%)`;
const style = `translateX(${Math.floor(progressValue - 100)}%)`;
return {
progress: `${progressValue}%`,
//progress: `${progress.value}%`,
webkitTransform: style,
mozTransform: style,
msTransform: style,
transform: style,
};
});
五、其他
5.1 如何增加计算MD5时的进度
- 修改file.vue文件,props中增加一计算md5的变量,然后在uploader-file-status下显示md5的进度
export default {
name: COMPONENT_NAME,
props: {
file: {
type: Object,
default() {
return {};
},
},
list: {
type: Boolean,
default: false,
},
//新增md5进度
cmd5Progress: {
type: Number,
default: 0,
},
},
...
<div class="uploader-file-status">
<span v-show="status !== 'uploading' && status !== 'cmd5'">{{
statusText
}}</span>
<span v-show="status !== 'uploading' && status === 'cmd5'"
>{{ statusText }}{{ cmd5Progress }}%</span
>
<span v-show="status === 'uploading'">
<span>{{ progressStyle.progress }} </span>
<em>{{ formatedAverageSpeed }} </em>
<i>{{ formatedTimeRemaining }}</i>
</span>
</div>
- 父组件调用修改
<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 ref="uploadBtn" :attrs="attrs"
><el-icon><Files /></el-icon> 选择文件</uploader-btn
>
<uploader-btn :directory="true"
><el-icon><Folder /></el-icon> 选择文件夹</uploader-btn
>
</div>
</uploader-drop>
<uploader-list>
<template v-slot:default="props">
<div class="file-panel">
<ul class="file-list">
<li v-for="file in props.fileList" :key="file.id">
<uploader-file
:class="'file_' + file.id"
ref="files"
:file="file"
:cmd5Progress="cmd5Progress[file.id]"
:list="true"
>
</uploader-file>
</li>
<div class="no-file" v-if="!props.fileList.length">
<!-- <i class="iconfont icon-empty-file"></i> 暂无待上传文件 -->
<el-empty :image-size="100">
<template #description>
<p>
暂无文件,请先<a class="upload" @click="upload">上传</a>
</p>
</template>
</el-empty>
</div>
</ul>
</div>
</template>
</uploader-list>
</uploader>
</div>
</template>
//定义一个数组接收进度变量
const cmd5Progress = reactive([]);
/**
* 计算md5,实现断点续传及秒传
* @param file
*/
function computeMD5(file) {
file.pause();
file.cmd5 = true; //文件状态为“计算md5...”
//单个文件的大小限制2G
let fileSizeLimit = 2 * 1024 * 1024 * 1024;
console.log("文件大小:" + file.size);
console.log("限制大小:" + fileSizeLimit);
if (file.size > fileSizeLimit) {
file.cancel();
ElMessage.error("限制上传文件大小不能超过2G");
return;
}
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 < chunks) {
loadNext();
} else {
let md5 = spark.end();
file.uniqueIdentifier = md5;
file.cmd5 = false; //取消计算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 + "块");
//计算cmd5进度,动态赋值
cmd5Progress[file.id] = Math.floor((currentChunk / chunks) * 100);
console.log(cmd5Progress[file.id]);
}
}
结果: