前端视频分⽚上传(blob)vuereactuni均适⽤
前⾔
开发过程中我们难免会遇到上传视频的需求。如果视频过⼤或者后端需要将前端上传的视频切割为播放更友好的m8u3格式,我们的分段上传视频就显得尤为重要
注意事项
下⾯的代码基于vue2.0框架使⽤混⼊的⽅法进⾏调⽤。需要注意的是如果你的项⽬使⽤了ESlint需要关闭while (true) 循环条件永恒进⼊的校验 or ⽤⾃⼰⽅法编写也是可以的
⽅案⼀:纯js写法(推荐)
封装对象
因后端处理⽅式统⼀ 前端市⾯上没有太多的视频分⽚插件 此作品给⼤家留出了绝对的⾃⽤空间 适配⼤多数需求。 需要⼤家根据⾃⼰需求请求⼀下接⼝就好了。
const upVideo={
file:null,//⽂件对象
size:0,//分⽚⼤⼩ kb
progressBar:0,//进度条 num%
underWayFn:null,//进度条改变触发函数
upOverFn:null,//上传完成触发函数
t:null,//定时器
// 初始化函数
init({
fileObj,//⽂件对象
size=2,//分⽚⼤⼩默认2 单位m
underWayFn=function(){},//进度条改变触发函数
upOverFn=function(){},//上传完成触发函数
}){
this.file=fileObj;
this.size=size*1024*1024;
this.underWayFn=underWayFn;
this.upOverFn=upOverFn;
// 判断是否是满⾜条件的视频对象满⾜条件调⽤this.upbegin()处理
this.upbegin();
},
// 上传⽂件
async upbegin(){
let videoTime =await this.videoLong();//视频播放时间
// 视频分⽚
let start =0, end =0, chunkArr=[], size =this.size;
let file=this.file;
function chuli(){
end += size;
var blob = file.slice(start, end);
start += size;
if(blob.size){
chunkArr.push(blob);
chuli(file);
}el{
return chunkArr
}
}
chuli();
//预请求接⼝然后this.inTurnto(chunkArr); 分⽚请求
// 分⽚请求主体
10个月宝宝辅食
// 分⽚请求主体
this.inTurnto(chunkArr);
console.log(videoTime,this.file)
},
/
/ 缓慢增长到⽬标进度条
changeProgressBar(num){
clearInterval(this.t)
this.t =tInterval(()=>{
if(this.progressBar == num){
clearInterval(this.t)
//上传完成
if(this.progressBar ===100){
this.upOverFn();//通知上传完成
this.clearUpVideo();//格式化重置
}
马祖光
}el{
this.progressBar++;
this.underWayFn(this.progressBar);//改变进度条通知
}
},50);
},
// 多个视频⼀⼀请求
inTurnto(chunkArr){
const chunkAllNum=chunkArr.length;//⽚段总数量
let count=0;//完成个数
chunkArr.forEach((item,index)=>{十五用英语怎么写
/
/ 模拟数据请求
tTimeout(()=>{
console.log(item,index)
count++;//增加当前进度
this.changeProgressBar(parInt(count/chunkAllNum*100));//改变进度},1000);
剑圣裴旻
})
天高云淡造句},
// 获取视频总时长
videoLong(){
return new Promi((resolve)=>{
var url =ateObjectURL(this.file);
var audioElement =new Audio(url);
audioElement.addEventListener("loadedmetadata",function(){ var hour =parInt((audioElement.duration)/3600);
if(hour<10){ hour ="0"+ hour;}
var minute =parInt((audioElement.duration %3600)/60);
if(minute<10){ minute ="0"+ minute;}
var cond = il(audioElement.duration %60);
if(cond<10){ cond ="0"+ cond;}
resolve(hour +":"+ minute +":"+ cond)
});
})
},
// 重置
clearUpVideo(){
this.file=null;
this.size=0;
this.progressBar=0;
this.underWayFn=null;
this.upOverFn=null;
this.t=null;
},
}
export default upVideo
上⽂中需要⾃⼰根据需求调接⼝的地⽅
init 中条件判断是否是满⾜条件的视频对象进⾏处理
upbegin 中预请求接⼝
inTurnto中模拟数据的请求
使⽤⽰例
这⾥没什么好说的 按照规则写就⾏
upVideo.init({
fileObj:file,//视频⽂件必传
size:3,//分⽚⼤⼩选填默认2单位M
underWayFn(num){//当前上传进度监听回调选填
console.log('进度',num)
},
upOverFn(){//上传完成⽣命周期选填
console.log('上传完成')
},
})
⽅案⼆:组件写法(不太推荐)
组件代码
/* 使⽤⽰例
使⽤时更改⾃⼰的接⼝地址使⽤到依赖axios
import upviedo from './upvideo.js'
mixins:[upviedo],
methods: {
preview(file) {
this.num++
if(this.num>=2)return
this.uploadViedo(上传⽂件对象,分⽚允许最⼤M(Num)).then(res=>{ console.log('总体完成')
}).catch(err=>{
console.log('总体失败')
})
},
}
this.Loading 变量当前上传进度
*/
export default{
data(){
return{
NowTotal:0,//当前
AllTotal:1,//总数
Loading:0,//当前进度%
clearT:0,//清除定时器
};
褚映红
},
mounted(){
/
/ 检测断⽹
window.addEventListener("offline",()=>{
console.log("已断⽹");
});
});
window.addEventListener("online",()=>{
console.log("⽹络已连接");
});
},
methods:{
// 上传进度
changeLoading(){
this.NowTotal++;
let ratio =(this.NowTotal *100)/(this.AllTotal *100)
ratio = und(ratio *100)
clearInterval(this.clearT)
this.clearT =tInterval(()=>{
this.Loading++;
if(this.Loading>=ratio)clearInterval(this.clearT);
},10)
},
// 视频长度
videoLong(file){
return new Promi((resolve,reject)=>{
var url =ateObjectURL(file);
var audioElement =new Audio(url);
audioElement.addEventListener("loadedmetadata",function(_event){ var hour =parInt((audioElement.duration)/3600);
if(hour<10){ hour ="0"+ hour;}
var minute =parInt((audioElement.duration %3600)/60);
if(minute<10){ minute ="0"+ minute;}
var cond = il(audioElement.duration %60);
if(cond<10){ cond ="0"+ cond;}
resolve(hour +":"+ minute +":"+ cond)
});
})
},
// file :⽂件 byte :每⽚字节⼤⼩单位M
async uploadViedo(file,byte =2){
var duration =await this.videoLong(file);
let chunkSize = byte *1024*1024//分⽚⼤⼩
let chunkArr =[];
if(file.size < chunkSize){
chunkArr.push(file.slice(0))
}el{
油闷笋
var start =0, end =0
while(true){
end += chunkSize
var blob = file.slice(start, end)
start += chunkSize
if(!blob.size){
break;
}
chunkArr.push(blob)
}
}
this.AllTotal = chunkArr.length;
return new Promi((ok,no)=>{
//预链接
this.$axios.post('https:',{
"video_number":this.AllTotal,//总共分为⼏⽚
"size":file.size,//⽂件总⼤⼩
"video_len": duration ||0,//视频长度
"video_len": duration ||0,//视频长度
"suffix":pe,//⽂件类型
}).then(res=>{
let all=[];
chunkArr.forEach((item,index)=>{
let p =new Promi((resolve,reject)=>{
var data =new FormData();
data.append('video', item)//视频主体
data.append('name', res.data.data)//视频名称
data.append('blob_num', index+1)//当前为第⼏段视频 data.append('total_blob_num',this.AllTotal)//总分为⼏段//上传主体
this.$axios.post('https:',data).then(res=>{
this.changeLoading();
resolve(res)
},err=>{
reject(err)
})
})
all.push(p);
})
半途而废造句Promi.all(all).then(res=>{
ok()
}).catch(err=>{
no(err)
})
}).catch(err=>{
no(err)
})
})
}
},
beforeDestroy(){
clearInterval(this.clearT)
}
}
使⽤⽰例
这⾥仅⽤element组件 编写⽰例 ⽅便理解cv到⾃⼰项⽬