前端视频分片上传(blob)vue react uni 均适用
生活随笔
收集整理的這篇文章主要介紹了
前端视频分片上传(blob)vue react uni 均适用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
開發過程中我們難免會遇到上傳視頻的需求。如果視頻過大或者后端需要將前端上傳的視頻切割為播放更友好的m8u3格式,我們的分段上傳視頻就顯得尤為重要
注意事項
下面的代碼基于vue2.0框架使用混入的方法進行調用。需要注意的是如果你的項目使用了ESlint需要關閉while (true) 循環條件永恒進入的校驗 or 用自己方法編寫也是可以的
方案一:純js寫法(推薦)
封裝對象
因后端處理方式統一 前端市面上沒有太多的視頻分片插件 此作品給大家留出了絕對的自用空間 適配大多數需求。 需要大家根據自己需求請求一下接口就好了。
const upVideo={file:null,//文件對象size:0,//分片大小 kbprogressBar:0,//進度條 num%underWayFn:null,//進度條改變觸發函數upOverFn:null,//上傳完成觸發函數t:null,//定時器// 初始化函數init({fileObj,//文件對象size=2,//分片大小 默認2 單位munderWayFn=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);}else{return chunkArr}}chuli();//預請求接口 然后this.inTurnto(chunkArr); 分片請求// 分片請求主體this.inTurnto(chunkArr);console.log(videoTime,this.file)},// 緩慢增長到目標進度條changeProgressBar(num){clearInterval(this.t)this.t = setInterval(() => {if(this.progressBar == num){clearInterval(this.t)//上傳完成if(this.progressBar === 100){this.upOverFn();//通知上傳完成this.clearUpVideo();//格式化重置} }else{this.progressBar++;this.underWayFn(this.progressBar);//改變進度條通知}}, 50);},// 多個視頻一一請求inTurnto(chunkArr){const chunkAllNum=chunkArr.length;//片段總數量let count=0;//完成個數chunkArr.forEach( (item,index) =>{// 模擬數據請求setTimeout(() => {console.log(item,index)count++;//增加當前進度this.changeProgressBar( parseInt(count/chunkAllNum*100) );//改變進度}, 1000);})},// 獲取視頻總時長videoLong(){return new Promise((resolve)=>{var url = URL.createObjectURL(this.file);var audioElement = new Audio(url);audioElement.addEventListener("loadedmetadata", function() {var hour = parseInt((audioElement.duration) / 3600);if (hour<10) { hour = "0" + hour; }var minute = parseInt((audioElement.duration % 3600) / 60);if (minute<10) { minute = "0" + minute; }var second = Math.ceil(audioElement.duration % 60);if (second<10) { second = "0" + second; }resolve(hour + ":" + minute + ":" + second)});})},// 重置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單位MunderWayFn(num){//當前上傳進度監聽回調 選填console.log('進度',num)},upOverFn(){//上傳完成生命周期 選填console.log('上傳完成')},})方案二:組件寫法(不太推薦)
組件代碼
/* 使用示例 使用時更改自己的接口地址 使用到依賴axios import upviedo from './upvideo.js'mixins:[upviedo],methods: {preview(file) {this.num++if(this.num>=2)returnthis.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 = Math.round(ratio * 100)clearInterval(this.clearT)this.clearT = setInterval(()=>{this.Loading++;if(this.Loading>=ratio)clearInterval(this.clearT);},10)},// 視頻長度videoLong(file){return new Promise((resolve,reject)=>{var url = URL.createObjectURL(file);var audioElement = new Audio(url);audioElement.addEventListener("loadedmetadata", function(_event) {var hour = parseInt((audioElement.duration) / 3600);if (hour<10) { hour = "0" + hour; }var minute = parseInt((audioElement.duration % 3600) / 60);if (minute<10) { minute = "0" + minute; }var second = Math.ceil(audioElement.duration % 60);if (second<10) { second = "0" + second; }resolve(hour + ":" + minute + ":" + second)});})},// file :文件 byte :每片字節大小 單位Masync 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))} else {var start = 0, end = 0while (true) {end += chunkSizevar blob = file.slice(start, end)start += chunkSizeif (!blob.size) {break;}chunkArr.push(blob)}}this.AllTotal = chunkArr.length;return new Promise((ok,no)=>{//預鏈接this.$axios.post('https:',{"video_number":this.AllTotal,//總共分為幾片"size":file.size,//文件總大小"video_len": duration || 0,//視頻長度"suffix":file.type,//文件類型}).then(res=>{let all=[];chunkArr.forEach((item,index)=>{let p = new Promise((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);})Promise.all(all).then(res=>{ok() }).catch(err=>{no(err)})}).catch(err=>{no(err)})})}},beforeDestroy(){clearInterval(this.clearT)} }使用示例
這里僅用element組件 編寫示例 方便理解cv到自己項目
<template><div class="hello"><el-uploadclass="upload-demo"dragaction="https://jsonplaceholder.typicode.com/posts/":on-change="preview":multiple="false"><i class="el-icon-upload"></i><div class="el-upload__text">將文件拖到此處,或<em>點擊上傳</em></div><div class="el-upload__tip" slot="tip">只能上傳jpg/png文件,且不超過500kb</div></el-upload></div> </template><script> import upviedo from './upvideo.js' export default {mixins:[upviedo],props: {msg: String},created(){},data() {return {num:0,};},computed:{},mounted(){},methods: {preview(file) {this.num++if(this.num>=2)returnconsole.log(file.raw)//上面代碼都可以無視 這里是最主要的//第一個參數 :視頻文件體 第二個參數:Num 每片視頻限制最大字節(單位M) 不傳默認2Mthis.uploadViedo(file.raw,2).then(res=>{console.log('總體完成')}).catch(err=>{console.log('總體失敗')})},}, } </script><style scoped></style>總結
本文僅提供思路 根據自己的需求靈活修改 文中不對的地方歡迎大佬指正,使用中出現問題歡迎評論或私信
收藏方便下次使用 開源不易,絕對原創 點個贊吧
總結
以上是生活随笔為你收集整理的前端视频分片上传(blob)vue react uni 均适用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端 视频标签 video的一些特殊属性
- 下一篇: 前端vue基本模板