很多时候我们都会用到大文件的上传,但是如果单一的上传会很慢,前端将2M发送一个请求,然后传给后台,后台将其拼接起来,当最后一个都传完,后台拼接存起来,返回我们所需要的路径
首先创建一个js文件
class fileUpload {
constructor(serviceUrl) {
this._serviceUrl = serviceUrl;
// this._bid = BID;
// this._fieldName = fieldName;
this._indexArr = [];
this._file;
this._name;
this._size;
this._shardSize = 2 * 1024 * 1024;
this._shardCount;
this._group = 0;
this._start = 0;
this._end;
this._fileSucess = false;
this.percentage = 0;
this._groupSize = 50;
this.successUpload = null;
this.percentageSend = null;
this._sendFile = {}; //保存整条数据时传给后台的数据
}
//单文件上传
upLoad(onefile) {
//初始化数据
this._group = 0;
this._start = 0;
this._end = 0;
this.percentage = 0; //进度
this._indexArr = [];
this._fileSucess = false;
this._file = onefile;
this._name = this._file.name; //文件名
this._size = this._file.size; //总大小
this._shardSize = 2 * 1024 * 1024; //以2MB为一个分片
this._shardCount = Math.ceil(this._size / this._shardSize); //总片数
this._uploadByCel(this._group * this._groupSize);//
}
//多分片时,每次只派发50个分片
_uploadByCel(startIndex) {
//本次循环将发出去的结尾block数;
let cCount = Math.min(this._shardCount, (this._group + 1) * this._groupSize);//总片数和50比较cCount取小的值
const nowtime=this.formatTime(new Date())
for (let i = startIndex; i < cCount; i++) {
this._start = i * this._shardSize;
this._end = Math.min(this._size, this._start + this._shardSize);//结束时总大小,和 开始的大小+之前的大小比较
let form = new FormData();//new一个form的实例,可以进行键值对的添加,
let request = new XMLHttpRequest()
//对form进行添加,form.get('data'),可以通过get方法获取到值
console.log(this._file.lastModified,"this._filethis._filethis._filethis._file")
form.append("data", this._file.slice(this._start, this._end)); //slice方法用于切出文件的一部分
form.append("name", this._name);
form.append("total", this._shardCount); //总片数
form.append("index", i + 1);
form.append("nowtime", this._file.lastModified);
form.get('nowtime')
form = this.initHttpHeader(form);
// form.append("folderid", this._bid);
// form.append("fieldname", this._fieldName);
if (request && form) {
request.open("POST", this._serviceUrl, true);
request.onload = (oEvent) => {
let aaa = JSON.parse(request.response);
let obj = aaa.data
if (obj && obj.end) {
this._fileSucess = true;
this.percentage = 100;
//构造保存数据时传给后台的数据
// if (obj.folderid)
// this._sendFile.folderid = obj.folderid;
// if (obj.foldername)
// this._sendFile.foldername = obj.foldername;
if (obj.name)
this._sendFile.name = obj.name;
if (obj.fileid)
this._sendFile.fileid = obj.fileid;
if (obj.realname)
this._sendFile.realname = obj.realname;
// if (obj.fieldname)
// this._sendFile.fieldname = obj.fieldname;
if (this.percentageSend != null)
this.percentageSend(this.percentage);
if (this.successUpload != null)
this.successUpload(true, this._sendFile,obj);
} else
if (this.successUpload != null)
this.successUpload(false);
if (obj && obj.index && obj.name != 'null' && obj.state && !obj.end) {
this._indexArr.push(obj.index);
this.percentage = Math.floor((this._indexArr.length / this._shardCount) * 100);
if (this.percentageSend != null)
this.percentageSend(this.percentage);
if (cCount != this._shardCount) {
if (this._indexArr.length == cCount) {
this._group++;
this._uploadByCel(this._group * this._groupSize);
}
}
}
if (obj && obj.index && !obj.state) {
if (!this._fileSucess)
this._reUpload(obj.index);
}
};
request.send(form);
}
}
// return this.percentage;
}
initHttpHeader(form) {
let out_form = form;
//----------TODO------------
// out_form.append("folderid", this._bid);
// out_form.append("fieldname", this._fieldName);
//--------------------------
return out_form;
}
//上传出现问题未上传的区片重现上传
_reUpload(index) {
this._start = index * this._shardSize;
this._end = Math.min(this._size, this._start + this._shardSize);
let form = new FormData();
let request = new XMLHttpRequest()
//append在form中元素的尾部添加内容
form.append("data", this._file.slice(this._start, this._end)); //slice方法用于切出文件的一部分
form.append("name", this._name);
form.append("total", data.length); //总片数
form.append("index", index);
form = this.initHttpHeader(form);
// form.append("folderid", this._bid);
// form.append("fieldname", this._fieldName);
if (request && form) {
request.open("POST", this._serviceUrl, true);
request.onload = (oEvent) => {
let obj = JSON.parse(request.response);
if (obj && obj.end) {
this._fileSucess = true;
}
if (obj && obj.index && obj.name != 'null' && obj.state) {
this._indexArr.push(obj.index);
this.percentage = Math.floor((this._indexArr.length / this._shardCount) * 100);
}
};
request.send(form);
}
}
formatTime(time, type, doubleNum) {
/**time:需要转换的时间;
* type:需要格式化的类型y(y)、y-m(m)、y-m-d(d)/y-m-d h:m:s(默认);
* doubleNum:月日时分秒的类型,例如2017-6('1') or 2017-06(默认)**/
let mydate = time ? new Date(time) : new Date();
let year = mydate.getFullYear();
let month = mydate.getMonth() + 1;
let day = mydate.getDate();
let hour = mydate.getHours();
let minute = mydate.getMinutes();
let second = mydate.getSeconds();
if (!doubleNum) {
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
}
if (type == 'y') {
return year;
} else if (type == "m") {
return year + '-' + month;
} else if (type == 'd') {
return year + '-' + month + '-' + day;
} else {
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ":" + second;
}
}
}
export default fileUpload;
这个是一个vue,
<template>
<div class="fileuploadbase">
<div class="fileuploadgroup">
<input type="file" name="file" id="fileinput" @change="fileUploadChanged" :multiple='false' style="display: none;" />
<el-button @click="fileButtonClick()" :disabled="!isUploadClick || (state!='ADD'&&state!='EDIT')" icon="el-icon-upload" size="mini" plain style='width"96px;height:38px;font-size: 14px;'>{{fileButtonText}}</el-button>
<div class="currentfilename" v-if="!isAutoUpload">{{ waitUploadFile }}</div>
<el-button @click="fileUploadStartup" v-show="isFileUploadStartupBottonShow" v-if="!isAutoUpload" size="mini" plain>点击上传</el-button>
</div>
<div v-show="currentFileName.length > 0">
<div class="fileuploadgroup" v-for="(item, index) in currentFileName" :key="index">
<div class="currentfilename" @click="handleFileDownloadClick(item)">{{ item.name }}</div>
<el-progress :text-inside="true" :stroke-width="18" :percentage="percentage" class="elprogress" v-show="isProgressVis && index==(currentFileName.length-1)"></el-progress>
<i class="el-icon-delete" title="删除文件" @click="handleFileDelClick(item)" v-show="isDeleteIconShow && (!isProgressVis || index!=(currentFileName.length-1)) && (state=='ADD'||state=='EDIT')" :style="{cursor: 'pointer'}"></i>
</div>
</div>
</div>
</template>
<script>
// import fileUpload from "./file-upload.js"
import fileUpload from "../../../../static/js/file-upload.js"
export default {
name: "file-upload",
data() {
return {
percentage: 0,
filesdata: [], //
fileUpload,
isDeleteIconShow: false,
isFileUploadStartupBottonShow: false,
isProgressVis: false,
currentFileName: [],
waitUploadFile: "",
isUploadClick: true
}
},
props: {
// 上传方式:true - 自动上传;false - 手动上传
isAutoUpload: {
type: String,
default: true,
},
// 单/多文件:true - 多文件;false - 单文件
isMultiple: {
type: String,
default: false,
},
// 状态:ADD - 新建;READ - 查看;EDIT - 修改
state: {
type: String,
default: null,
},
// 上传服务地址
fileUploadURL: {
type: String,
default: null,
},
// 已有附件集合
histFileArr: {
type: Array,
default: [],
}
},
computed: {
fileButtonText() {
if (this.currentFileName.length == 0) {
return '上传数据';
} else {
return '继续添加';
}
}
},
methods: {
fileUploadChanged() {
this.filesdata = this.$el.getElementsByTagName("input")[0].files;//this.$el.getElementsByTagName方法可返回带有指定标签名的对象的集合。
if (this.filesdata.length == 0) return;
this.isDeleteIconShow = true;
this.isFileUploadStartupBottonShow = true;
this.isProgressVis = false;
this.percentage = 0;
this.waitUploadFile = this.filesdata[0].name;
if (this.isAutoUpload) {
this.fileUploadStartup();
}
},
fileUploadStartup() {
this.isUploadClick = false;
this.isDeleteIconShow = false;
this.isFileUploadStartupBottonShow = false;
if (!this.isMultiple) {
this.fileDelOper(this.currentFileName[0]);// 进行删除操作
this.currentFileName = [];
}
this.isProgressVis = true;
this.currentFileName.push({ name: this.filesdata[0].name });
this.fileUpload = new fileUpload(this.fileUploadURL);
console.log(this.filesdata[0],"this.filesdata[0]")
this.fileUpload.upLoad(this.filesdata[0],this.formatTime(new Date()));
this.fileUpload.percentageSend = this.percentageSend;
this.fileUpload.successUpload = this.successUpload;
},
//接收上传的百分值回调
percentageSend(perNum) {
this.percentage = perNum;
},
successUpload(success, field,value) {
if (success) {
if (this.percentage < 100) return;
this.isDeleteIconShow = true;
this.isFileUploadStartupBottonShow = false;
this.isProgressVis = false;
this.isUploadClick = true;
document.getElementById("fileinput").value = "";
this.waitUploadFile = "";
this.successvalue=value
this.$emit('successvalue',this.successvalue);
this.$message({
message: '文件上传成功',
type: 'success'
});
}
},
// 点击文件后面的删除按钮
handleFileDelClick(item) {
this.filesdata = [];
document.getElementById("fileinput").value = "";
for (let i = 0; i < this.currentFileName.length; i++) {
if (this.currentFileName[i].name == item.name) {
this.fileDelOper(item);// 进行删除操作
this.currentFileName.splice(i, 1); //删除下标为i的元素
return this.currentFileName;
}
}
this.isDeleteIconShow = false;
this.isFileUploadStartupBottonShow = false;
this.isProgressVis = false;
},
// 点击选取文件
fileButtonClick() {
document.getElementById('fileinput').click();
},
// 删除操作
fileDelOper(val) {
this.$emit("fileDelOper", val);
},
// 点击文件下载
handleFileDownloadClick(val) {
this.$emit("fileDownload",val);
}
},
watch: {
histFileArr() {
if (!this.histFileArr) {
this.isDeleteIconShow = false;
this.currentFileName = [];
return;
}
this.isDeleteIconShow = true;
this.currentFileName = this.histFileArr;
}
},
created() {
if (!this.histFileArr) {
this.isDeleteIconShow = false;
this.currentFileName = [];
return;
}
this.isDeleteIconShow = true;
this.currentFileName = this.histFileArr;
}
}
</script>
<style scoped>
a {
color: #42b983;
}
</style>
只要引进这两个然后就写页面,在template中
<template>
<div class="new_con">
<el-card class="box-card">
<el-form
:model="sjgxform"
class="form_protocol"
label-position="right"
style="margin:0 auto;width:80%"
>
<el-form-item label="大文件上传" style="text-align: left;">
<div class="hello" style="width:75%;margin-left:27px;display: inline-block;">
<div class="operbuttongroup" >
<file-upload
isAutoUpload="true"
isMultiple="false"
state="ADD"
:fileUploadURL="fileUploadURL"
:histFileArr="histFileArr"
@fileDelOper="fileDelOper"
@fileDownload="fileDownload"
@successvalue='successvalue'
></file-upload>
</div>
</div>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import FileUpload from "../../components/bigfiles.vue";
export default {
components: {
FileUpload
},
computed: {
},
data() {
return {
//大文件上传
fileUploadURL: window.bigupload, // 上传服务地址
histFileArr: [] // 已有附件集合
};
},
watch: {
},
methods: {
//大文件上传
fileDelOper(val) {},
fileDownload(val) {},
successvalue(val) {
console.log(val,"大文件上传成功了,然后就可以看到返回的值了")
this.sjgxform.fjList.push({
PID: this.$route.query.id,
WDFL: "3",
WDMC: val.WDMC,
WJLJ: val.WJLJ,
CJRID: this.$store.state.Login.userInfo.ID
});
}
},
mounted() {
}
};
</script>
<style scoped>