@1 前端如何上传大文件呢? 接下来我们模拟前端上传大文件的操作。首先需要安装axios和spark-md5这两个插件。
1 定义一个input 类型为file的标签,给标签绑定事件。image图片 标签,以及一个total全局常
量的进度条,定义断点续传的变量 let isupload = false ; var total = 0;
<input type="file" @change="changeFile" /> <image src="image"> <video src="" />
2 文件在上传的过程中一般会采用 二进制 base64 buffer格式的。如果是图片的一般采用
base64格式的。
3 首先我们定义一个方法以什么格式读取文件。第一个参数为上传的文件,第二个参数格式。
const fileParse(file, type='base64') {
return new Promise(resolve=>{
const fileRead = new FileReader() // 主要是用来new读取文件的实例化对香
if(type==='base64') { // 进行判断需要转为什么格式的文件
fileRead.readAsDataURL(file) // 转为base64格式的
}else if(type==='buffer') {
fileRead.readAsArrayBuffer(file) // 转为Buffer格式的
}
fileRead.onload(e=>{
resolve(e.target.result) // 文件转化成功后的回调函数
})
})
}
4 这时候我们开始选择文件进行上传 触发changeFile这个方法 先上传图片
async changeFile (file) {
if(! file) return
file = file.target.files[0] // 获取上传的图片
const res = await fileParse(file,'base64') // 调用3封装的方法读取文件 转为base64
result = await axios.post('/uploadImage', qs.stringfy({
chunk:encodeURLComponent(res) // 上传文件的参数 base64编码
filename:file.name // 文件的名称
}),{
headers:{
“Content-Type”:“application/x-www-form-urlencoded”
}
})
result = result.data // 获取上传成功后的数据
document.queryselector('image').src = result.path // 将获取的图片路径赋值给图片标
}
5 选择大文件进行切片上传: 思路将大文件进行分片上传 上传成功后进行合并
async changeFile (file) {
if(!file) return
file = file.target.files[0] // 获取上传的文件
// 第一步将上传的文件解析为buffer数据 调用上面封装的方法
const res = await fileParse(file,‘buffer’)
spark = new SparkMD5.ArrayBuffer() // 使用sparkMD5这个第三方插件生成hsah值
hash, // 定义hash值
suffix, // 定义后缀名 格式
spark.append(res);
hash = spark.end() // 获取hash值
suffix = /\.([0-9a-zA-Z]+)$/i.exec(file.name)[1] // 获取文件格式
// 第二步 创建切片
let parList = [ ] // 切片的集合
partsize = file.size / 100 // 定义每个切片的大小 给切片设置100份
cur = 0; 切片的起始值
for(let i = 0; i < 100; i++){
let item = {
chunk:file.slice(cur,cur+partsize), // 每个切片
filename:`${hash}_${i}.${suffix}` // 切片的名称 hash-1.mp4 格式的
}
cur+=partsize // 重新计算起始值
parList.push(item) // 所有的切片集合
}
this.hash = hash // 给全局的hash和parList赋值方便下面方法的获取
this.parList = parList
this.sendRequest() // 调用上传切片的方法
}
// 第三步 定义切片上传的方法
async sendRequest() {
// 创建100个切片上传的集合
const requestList = [ ]
this.parList.forEach( (item ,index) = > {
let fn = ()=>{
let formData = new FormData()
formData.append('chunk',item.chunk)
formData.append('filename',item.name)
return axios.post('/upload',formData,{
headers:{'Content-Type':'multipart/form-data'}
}).then(res=>{
res = res.data
if(res.code===0){
this.total+=1 // 这个total可以在全局定义为0 定义进度条
this.parList.splice(index,i) // 将上传完的切片移除,后期继续上
传的话就不会重复上传已经上传完成的切片了
}
})
}
requeList.push(fn)
})
let i = 0; //定义的i用来记录切片上传了多少个
let compte = async ()=>{ // 定义切片上传完成后 合并切片请求的方法
let result = await axios.get('/merge',{
hash:this.hash
})
res = resullt.data
this.video = result.path // 服务器返回上传文件的地址进行赋值,这里用的是
视频
}
// 递归函数执行 上传切片
let send = async ()=>{
if(isupload) return //利用isupload这个变量在这里控制文件是否继续上传
if(i>=requeList.length) {
// 上传完了 需要调用合并切片的请求了
complete()
return
}
await requeList[i]() // 执行每一个切片上传的方法
i++;
send()
}
send()
}
第四步断点续传:可以给两个按钮控制isupload值得变化,重新调用方法
<button @click="stop">暂停</button> <button @click="start">继续</button>
stop(){
this.isupload = true
this.sendRequest() // 再次调用切片上传的方法
},
start() { this.isupload = false;this.sendRequest() }
前端之大文件断点上传
最新推荐文章于 2024-05-01 12:41:06 发布