前言:
最近重构公司项目核心内容就是大文件的上传功能,文件基本上都是几个G的,着手的是原生的input标签file,
大文件我们首先考虑到一个分片上传这样的功能我们先来说一说分片的好处
好处: 分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了 .
可想而知如果不分片会造成文件的丢失,下一次上传从新开始上传,极大的浪费资源一方面给用户体验也不是很好
CSS样式:
修改前:修改前是和其他表单共用的弹窗
修改后:这里是另外单独的弹窗把上传事件加到确定事件上了
技术栈:
框架Vue2.0+Ant Design Vue组件库
代码展示:
template中
<a-modal
title="文件上传"
:width="900"
:visible="visible"
:confirmLoading="confirmLoading"
okText="点击上传文件"
@ok="handleSubmit"
@cancel="handleCancel"
>
<!-- UI组件库的加载效果 -->
<a-spin :spinning="confirmLoading">
<a-row>
<a-col :span="12" :offset="6">
<a-form :form="form" :label-col="{ span: 7 }" :wrapper-col="{ span: 10 }" has-feedback>
<a-form-item label="模型压缩包" :label-col="{ span: 7 }" :wrapper-col="{ span: 10 }">
<div class="ipts">
请选择模型压缩包<input
v-if="!cancel_img"
type="file"
id="file"
name="file"
class="uploads"
@change="handleFiles"
/>
</div>
<!-- 文件上传的名称 -->
<div class="fileInfo">{{ filesName }}</div>
</a-form-item>
</a-form>
</a-col>
</a-row>
</a-spin>
</a-modal>
script中
export default {
data() {
return {
filesName: '', //获取上传文件的名称
cancel_img: '',
tton: 0,
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
// 机构行样式
labelCol_JG: {
xs: { span: 24 },
sm: { span: 3 },
},
wrapperCol_JG: {
xs: { span: 24 },
sm: { span: 20 },
},
}
},
methods: {
// 获取上传文件的名称
handleFiles(event) {
this.filesName = event.target.files[0].name
},
save() {
// 每个文件切片大小定为1M(1024*1024字节)(需要跟服务器协商好)
var BYTES_PER_SLICE = (1 << 20) * 100 //这里定义的是每个包分的是100MB
// 已发送的数量
var hasSendNum = 0
// 总切片数
var totalSlices
this.tton == 1
this.confirmLoading = true //loading加载
// 拿出选中的第一个文件
var file = document.getElementById('file').files[0]
// 文件的总字节数
var totalSize = file.size
// 当前片数
var index = 0
// 分片的开始、结束(不含)
var start, end
// 文件名
var fileName = file.name
// 初始化已发送数量为0
hasSendNum = 0
// 计算文件切片总数(向上取整)
totalSlices = Math.ceil(file.size / BYTES_PER_SLICE)
// 不断循环将切片上传
while (index < totalSlices) {
start = index * BYTES_PER_SLICE
end = start + BYTES_PER_SLICE
var slice = file.slice(start, end) //切割文件
this.handleChangeupload(slice, index++, fileName, totalSlices, totalSize)
}
},
handleChangeupload(slice, index, fileName, totalSlices, totalSize) {
var retry = 1
var FormDate = new FormData()
FormDate.append('totalSlices', totalSlices) //总数
FormDate.append('index', index) //当前数
FormDate.append('totalSize', totalSize) //字节数
FormDate.append('filename', fileName) //文件名
FormDate.append('file', slice) //文件流
addThreeDUrl(FormDate).then((res) => {//调用上传接口
if (res.code == 200) {
this.$message.success('上传成功')
this.confirmLoading = false //关闭loading加载
this.visible = false //关闭弹窗
//nextTick 函数是在下一次dom更新后回调,
//这就可以实现先执行的上面的代码,让input[file]节点消失,
//然后再dom更新后回调该函数,又执行了让input[file]节点显示,这样就实现了刷新
this.cancel_img = true
this.$nextTick(() => {
this.cancel_img = false
})
this.filesName = '' //清除上传文件名称
} else {
this.$message.console.error('上传失败')
this.confirmLoading = false //关闭loading加载
}
})
},
// 点击上传文件按钮
handleSubmit() {
if (this.filesName != '') {
this.save()
} else {
this.$message.error('请选择模型压缩包再点击上传')
}
},
// 取消按钮
handleCancel() {
this.cancel_img = true
this.$nextTick(() => {
this.cancel_img = false
})
this.filesName = '' //清除上传文件名称
this.visible = false
},
},
}
CSS样式
.ipts {
width: 210px;
height: 128px;
padding: 4px 10px;
line-height: 127px;
position: relative;
border: 1px solid #999;
text-decoration: none;
color: #333;
background-color: #fafafa;
text-align: center;
border: 1px dashed #999;
border-radius: 5px;
cursor: pointer;
}
.uploads {
position: absolute;
overflow: hidden;
right: 0;
top: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
注意:请求接口只能用POST 切记不能用GET
商务插播:网站 清悠业务网
每天签到奖励现金哦!
快来和我一起领取吧!
网址:点击跳转
每天免费领取2000名片赞
建议收藏网站可天天领取
总结:
以上就是所有内容和代码,欢迎大家指教