问题描述:项目里需要上传1G以上的iso文件,不使用插件
解决方法:
<template>
<div class="file-panel">
<!-- -->
<input type="file" id="file" ref="uploadBtn" accept=".iso"/>
<div>
<div class="file-list">
<ul>
<li class="file-item" v-for="(file,index ) in fileList" :key="index">
<span
style="margin-right:30px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;font-size:14px;width:280px"
>{{file.name}}</span>
<span style="margin-right:10px;font-size:14px">{{file.size}}G</span>
<span style="margin-right:15px;font-size:14px">{{file.date}}</span>
<a title="移除" @click="remove(file,index)">
<i class="el-icon-delete"></i>
</a>
<el-progress :percentage="percentage[index]"></el-progress>
</li>
</ul>
</div>
</div>
<!-- <button id="upload" @click="upload">上传</button> -->
</div>
</template>
<script>
import SparkMD5 from 'spark-md5';
export default {
data() {
return {
index: -1,
shardSize: 2 * 1024 * 1024, //以2MB为一个分片
dataBegin: null, //开始时间
dataEnd: null, //结束时间
action: false,
fileList: [], //存放文件的名称、上传文件的时间和上传进度
percentage: [],
md5:''
};
},
methods: {
//点击按钮
upload() {
this.dataBegin = new Date();
let file = document.getElementById("file").files[0];
let start = parseInt(start, 10) || 0;
let end = parseInt(end, 10) || (file.size - 1);
this.isUpload(file);
console.log('点击我,上传呀')
},
//删除文件
remove(file, index) {
console.log('我被删除了')
this.fileList.splice(index, 1);
},
//MD5值
computeMD5(file){
var running=false
if (running) {
return;
}
//这里需要用到File的slice( )方法,以下是兼容写法
var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
//file = input.files[0],
chunkSize = 2097152, // 以每片2MB大小来逐次读取
chunks = Math.ceil(file.size / chunkSize),
currentChunk = 0,
spark = new SparkMD5(), //创建SparkMD5的实例
time,
fileReader = new FileReader();
let promise = new Promise((reslove, reject) => {
fileReader.onload = function (e) {
spark.appendBinary(e.target.result); // append array buffer
currentChunk += 1;
if (currentChunk < chunks) {
loadNext();
} else {
running = false;
console.log("Finished loading!");
reslove(spark.end())
}
};
fileReader.onerror = function () {
running = false;
reject()
};
})
function loadNext() {
var start = currentChunk * chunkSize,
end = start + chunkSize >= file.size ? file.size : start + chunkSize;
fileReader.readAsBinaryString(blobSlice.call(file, start, end));
}
running = true;
loadNext();
return promise
},
//检查是否上传
isUpload(file) {
let self =this
let flag=true
let form = new FormData(); //构造一个表单,FormData是HTML5新增的
this.computeMD5(file)
.then(res => {
let md5 = res
this.$http.post("/virtualDrive/isUpload", {
md5: md5
})
.then(({ data }) => {
let uuid = data.fileId;
let date = data.date;
if (data.flag == "0") {
//没有上传过文件
this.UpLoad(file, uuid, md5, date);
} else if (data.flag == "1") {
//已经上传部分文件
this.UpLoad(file, uuid, md5, date);
} else if (data.flag == "2") {
//已经上传过文件
this.$message.success("文件已经上传过,秒传了!!");
}
});
})
.catch(err => {
// 获取MD5失败
this.$message.warn('失败')
})
},
//上传文件
UpLoad(file, uuid, md5, date) {
let name = file.name;
let size = file.size;
let shardCount = Math.ceil(size / this.shardSize); //总片数
if (this.index > shardCount) {
return;
} else {
if (!this.action) {
this.index += 1; //只有在检测分片时,i才去加1; 上传文件时无需加1
}
}
//计算每一片的起始与结束位置
var start = this.index * this.shardSize;
var end = Math.min(size, start + this.shardSize);
//构造一个表单,FormData是HTML5新增的
var form = new FormData();
if (!this.action) {
form.append("action", "check"); //检测分片是否上传
} else {
form.append("action", "upload"); //直接上传分片
form.append("data", file.slice(start, end)); //slice方法用于切出文件的一部分
}
form.append("uuid", uuid);
form.append("md5", md5);
form.append("date", date);
form.append("name", name);
form.append("size", size);
form.append("total", shardCount); //总片数
form.append("index", this.index + 1); //当前是第几片
let index = this.index + 1;
//按大小切割文件段
let data = file.slice(start, end);
let r = new FileReader();
r.readAsArrayBuffer(data);
r.onload = e => {
let spark = new SparkMD5.ArrayBuffer()
spark.append(e.target.result);
let partMd5= spark.end();
form.append("partMd5", partMd5);
//文件 把数字格式化为指定的长度
let fileSize = parseFloat(file.size / 1024 / 1024 / 1024).toPrecision(2);
//去重
let [mark, fileIndex] = [false, 0];
this.fileList.forEach((item, i) => {
if (item.name == file.name) {
mark = true;
fileIndex = i;
}
});
if (!mark) {
this.fileList.push({
name: file.name,
date: this.dataBegin.Format("HH:mm:ss"),
size: fileSize
});
this.percentage.push(
Number(((index / shardCount) * 100).toFixed(2))
);
} else {
let val = Number(((index / shardCount) * 100).toFixed(2));
val = Number(val) > 100 ? 100 : Number(val);
this.$set(this.percentage, fileIndex, val);
}
this.$http
.post("/virtualDrive/upload", form, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(({ data }) => {
console.log("上传接口");
let fileuuid = data.fileId;
let flag = data.flag;
if (flag == "2") {
this.$message.success("上传成功!");
} else if (flag != "2") {
//服务器返回该分片是否上传过
if (flag == "0") {
//未上传,继续上传
this.action = true;
} else if (flag == "1") {
//pending状态
this.action = false;
}
this.UpLoad(file, uuid, md5, date);
}
});
};
}
},
computed: {},
mounted() {
this.$eventBus.$on("upload", () => { //父组件的按钮使用
this.upload();
});
},
watch: {}
};
</script>
<style lang="stylus" scoped>
.file-panel
width 100%
margin-top 10px
.file-list
height 160px
max-height 160px
overflow-y auto
margin-top 20px
.file-item
height 50px
line-height 50px
padding 0 10px
background-color #fff
z-index 1
display inline-block
border-bottom 1px solid #ccc
display flex
flex-direction row
flex 1
.progress
width 200px
height 20px
margin-left 30px
</style>
<style lang="stylus">
.file-panel
.el-progress
margin-top 15px
margin-left 30px
.el-progress-bar__outer
height 0 !important
</style>