前端vue大文件分片上传,vue断点续传插件
许多项目都使用上传文件。如果是几米长的话,会传的很快。如果是大文件呢?介绍了Vue大文件上传和断点续传的实现。有兴趣的可以看看。
目录
文件上传的两种方案基于文件流(form-data)客户端,将文件转换成base64大文件,上传得到file对象转换成ArrayBuffer对象,创建切片,发送请求。所有切片发送成功后,断点续传的代码摘要是one more thingformformdata . append()
文件上传的 2 套方案
基于文件流(form-data)
默认情况下,element-ui框架的上传组件基于文件流。
数据格式:表单-数据;
传输的数据:文件流信息;文件名文件名
客户端把文件转换为 base64
通过fileRead.readAsDataURL(文件)转换成base64字符串后,要用encodeURIComponent编译后再发送。发送的数据由qs.stringify处理,请求头添加了 content-type : application/x-www-form-urlencoded
大文件上传
首先,借助element-ui构建下一个页面。因为您想要定制上传的实现,所以el-upload组件的auto-upload应该设置为false;Action是必需的参数,您可以在此处不输入任何值。
模板
div id=应用程序
!-上传组件-
el-upload动作拖动:auto-upload= false :show-file-list= false :on-change= handle change
i class=el-icon-upload/i
El-upload _ _ text 将文件拖到此处,或者emclick upload /em/div。
class= El-upload _ _ tip slot= tip Video/div,大小不超过200M
/El-上传
!-进度显示-
div class=进度框
Span上载进度:{{ percent.toFixed() }}%/span
El-button type= primary size= mini @ click= handleClickBtn { { upload btnTextFilter } }/El-button
/div
!-成功显示上传的视频-
div v-if=videoUrl
视频:src=videoUrl 控件/
/div
/div
/模板
获取到文件对象并转成 ArrayBuffer 对象
它被转换为ArrayBuffer,因为库SparkMD5将用于生成哈希值和命名文件。
异步handleChange(文件){
const fileObj=file.raw
尝试{
const buffer=wait this . filetobuffer(file obj)
console.log(缓冲区)
}catch(e){
console.log(e)
}
}
打印缓冲结果如下
注意:上传前函数和更改时函数的参数有File,但更改时的文件不是File对象。要获得file对象,需要遍历file.raw这里,fileReader类用于将File对象传递给ArrayBuffer对象。因为这是一个异步过程,所以它被封装为一个承诺:
//将File对象转换为ArrayBuffer
fileToBuffer(文件){
返回新承诺((解决,拒绝)={
const fr=new FileReader()
fr.onload=e={
解决(例如,目标.结果)
}
fr.readAsArrayBuffer(文件)
fr.onerror=()={
拒绝(新错误(“转换文件格式时出错”))
}
})
}
创建切片
一个文件可以按固定的大小或数量分成几个部分。为了避免js使用的IEEE754二进制浮点运算标准可能带来的错误,我决定对文件进行固定大小的切割,将每个切片的大小设置为2M,即2m=21024 kb=21024 * 1024 b=2097152 b。文件是用Blob.slice()剪切的
//以固定大小分割文件(2M)。注意,这里同时声明了多个常量。
const chunkSize=2097152,
ChunkList=[],//保存所有切片的数组
chunistlength=math . ceil(file obj . size/chunk size),//计算多个切片的总数。
后缀=/\。([0-9a-z]) $/。exec(file obj . name)[1]//文件扩展名
//根据文件内容生成哈希值
const spark=new SparkMD5。ArrayBuffer()
spark.append(缓冲)
const hash=spark.end()
//生成切片,后端需要传递的参数是字节块和每个块的文件名。
curchunk=0//切片时的初始位置
for(设I=0;i chunkListLengthi ) {
常量项目={
chunk: fileObj.slice(curChunk,curChunk chunkSize),
文件名:` ${hash}_${i} .${suffix}` //文件名规则按照哈希_1.jpg命名
}
curChunk=chunkSize
chunkList.push(项目)
}
console.log(chunkList)
选择一个文件后将打印得到诸如下图的结果
发送请求
发送请求可以是并行的或是串行的,这里选择串行发送。每个切片都新建一个请求,为了能实现断点续传,我们将请求封装到函数【数学】函数里,用一个数组请求列表来保存请求集合,然后封装一个派遣函数,用于请求发送,这样一旦按下暂停键,可以方便的终止上传,代码如下:
sendRequest() {
常量请求列表=[] //请求集合
this.chunkList.forEach(item={
const fn=()={
常量表单数据=新表单数据()
formData.append(chunk ,item.chunk)
formData.append(文件名,项目。文件名)
返回axios({
网址:“/单3”,
方法: post ,
标头:{ Content-Type : multipart/form-data },
数据:表单数据
}).然后(res={
if (res.data.code===0) { //成功
if (this.percentCount===0) {
这个。百分比计数=100/this。区块列表。长度
}
这个。百分比=这个。百分比计数//改变进度
}
})
}
请求列表。推送(fn)
})
设i=0 //记录发送的请求个数
const send=async ()={
//如果(暂停)返回
if (i=requestList.length) {
//发送完毕
返回
}
等待请求列表[我]()
我
发送()
}
send() //发送请求
},
爱可信部分也可以直接写成下面这种形式:
axios.post(/single3 ,formData,{
标题:{ Content-Type : multipart/form-data }
})
所有切片发送成功后
根据后端接口需要再发送一个得到请求并把文件的混杂值传给服务器,我们定义一个完成方法来实现,这里假定发送的为视频文件
const complete=()={
axios({
URL:“/merge”,
方法:“得到”,
参数:{ hash: this.hash }
}).然后(res={
if (res.data.code===0) { //请求发送成功
this.videoUrl=res.data.path
}
})
}
这样就能在文件发送成功后在页面浏览到发送的视频了。
断点续传
首先是暂停按钮文字的处理,用了一个过滤器,如果上传值为真实的则显示"暂停",否则显示"继续":
过滤器:{
btnTextFilter(val) {
返回瓦尔。暂停 : 继续
}
}
当按下暂停按钮,触发handleClickBtn方法
handleClickBtn() {
this.upload=!这个。上传
//如果不暂停则继续上传
如果(这个。上传)这个。发送请求()
}
在发送切片的派遣方法的开头添加如果(!this .上传)返回,这样只要上传这个变量为错误的就不会继续上传了。为了在暂停完后可以继续发送,需要在每次成功发送一个切片后将这个切片从组块列表数组里删除this.chunkList.splice(索引,1)
代码汇总
模板
div id=应用程序
!-上传组件-
El-上传动作拖动:auto-upload=“false”:show-file-list=“false”:on-change=“处理更改”
i class=el-icon-upload/i
div class=el-upload__text 将文件拖到此处,或全身长的点击上传/em/div
div class= El-upload _ _ tip slot= tip 大小不超过200米的视频/div
/El-上传
!-进度显示-
div class=进度框
跨度上传进度:{{ percent.toFixed() }}%/span
El-button type= primary size= mini @ click= handleClickBtn { { upload btnTextFilter } }/El-button
/div
!-展示上传成功的视频-
div v-if=videoUrl
视频:src=videoUrl 控件/
/div
/div
/模板
脚本
从"火花md5 "导入SparkMD5
从" axios "导入爱可信
导出默认值{
名称: App3 ,
过滤器:{
btnTextFilter(val) {
返回瓦尔。暂停 : 继续
}
},
data() {
返回{
百分比:0,
视频Url: ,
上传:真的,
百分比计数:0
}
},
方法:{
异步handleChange(文件){
如果(!文件)返回
这个百分比=0
this.videoUrl=
//获取文件并转成数组缓冲对象
const fileObj=file.raw
让缓冲区
尝试{
buffer=等等这个。文件缓冲区(文件对象)
} catch (e) {
console.log(e)
}
//将文件按固定大小(2M)进行切片,注意此处同时声明了多个常量
const chunkSize=2097152,
chunkList=[],//保存所有切片的数组
块列表长度=数学。天花板(文件对象。大小/块大小),//计算总共多个切片
后缀=/\。([0-9A-z] )$/.exec(fileObj.name)[1] //文件后缀名
//根据文件内容生成混杂值
const spark=new SparkMD5 .ArrayBuffer()
火花.附加(缓冲)
const hash=spark.end()
//生成切片,这里后端要求传递的参数为字节数据块(组块)和每个数据块的文件名(文件名)
设curChunk=0 //切片时的初始位置
对于(设I=0;i chunkListLengthi ) {
常量项目={
chunk: fileObj.slice(curChunk,curChunk chunkSize),
文件名:` ${hash}_${i} .${suffix}` //文件名规则按照哈希_1.jpg命名
}
curChunk=chunkSize
chunkList.push(项目)
}
这个。区块列表=区块列表//发送请求要用到
this.hash=hash //发送请求要用到
this.sendRequest()
},
//发送请求
sendRequest() {
常量请求列表=[] //请求集合
this.chunkList.forEach((item,index)={
const fn=()={
常量表单数据=新表单数据()
formData.append(chunk ,item.chunk)
formData.append(文件名,项目。文件名)
返回axios({
网址:“/单3”,
方法: post ,
标头:{ Content-Type : multipart/form-data },
数据:表单数据
}).然后(res={
if (res.data.code===0) { //成功
if (this.percentCount===0) { //避免上传成功后会删除切片改变组块列表的长度影响到百分比计数的值
这个。百分比计数=100/this。区块列表。长度
}
这个。百分比=这个。百分比计数//改变进度
this.chunkList.splice(index,1) //一旦上传成功就删除这一个组块,方便断点续传
}
})
}
请求列表。推送(fn)
})
设i=0 //记录发送的请求个数
//文件切片全部发送完毕后,需要请求/合并接口,把文件的混杂传递给服务器
const complete=()={
axios({
URL:“/merge”,
方法:“得到”,
参数:{ hash: this.hash }
}).然后(res={
if (res.data.code===0) { //请求发送成功
this.videoUrl=res.data.path
}
})
}
const send=async ()={
如果(!this .上传)返回
if (i=requestList.length) {
//发送完毕
完成()
返回
}
等待请求列表[我]()
我
发送()
}
send() //发送请求
},
//按下暂停按钮
handleClickBtn() {
this.upload=!这个。上传
//如果不暂停则继续上传
如果(这个。上传)这个。发送请求()
},
//将文件对象转为数组缓冲
文件缓冲区(文件){
返回新承诺((解决,拒绝)={
const fr=new FileReader()
fr.onload=e={
解决(例如,目标。结果)
}
fr.readAsArrayBuffer(文件)
fr.onerror=()={
拒绝(新错误(转换文件格式发生错误))
}
})
}
}
}
/脚本
样式范围。进度框{
框大小:边框-框;
宽度:360px
显示器:flex
justify-content:space-between;
对齐-项目:居中;
页边距-顶部:10px
填充:8px 10px
背景色:# ECF 5 ff;
字体大小:14px
边框-半径:4px
}
/风格
效果如下:
One More Thing
FormData
FormData用于在此发送数据。如果编码类型设置为“多部分/表单数据”,它将使用与表单相同的格式。
FormData.append()
新值将被添加到FormData对象中的现有键中,或者如果该键不存在,则将添加该键。该方法可以传递三个参数,formdata.append (name,value,filename),其中Filename是可选参数,是传递给服务器的文件名。当blob或文件用作第二个参数时,Blob对象的默认文件名是 Blob 。对象的默认文件名是文件的名称。
关于Vue大文件上传和断点续传实现的这篇文章到此为止。关于Vue大文件上传和断点续传的更多信息,请搜索我们之前的文章或者继续浏览下面的相关文章。希望大家以后能多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。