背景
由於我司業務關係,需實現相容IE8+瀏覽器的視訊上傳功能,且支援多選斷點上傳。故藉助Baidu WebFE(FEX)團隊開發的webuploader檔案上傳外掛實現此業務功能。
檔案上傳的一般聯調步驟
1.js端認證(主要是判斷視訊是否已存在,若已存在,返回視訊已上傳的檔案大小,只需要判斷一次):
-
第一步:計算視訊檔案的md5,視訊檔案越大、計算md5的時間越久
-
第二步:獲取視訊檔案的總大小
-
第三步:把視訊名稱、檔案總大小、視訊檔案的md5字串傳輸到tokenUrl
2.返回json的引數:
-
success:驗證是否成功
-
fileMd5:視訊檔案md5
-
start:已上傳的大小(沒上傳過的返回0,已上傳部分則返回對應已上傳的大小值,例如:30000位元組,已上傳20000位元組,則返回20000)
3.驗證通過後,js端上傳(視訊檔案大的,分割的次數也越多)
- 第一步:根據視訊檔案的總大小、設定每次分割視訊流的大小
- 第二步:把視訊檔案的md5字串、
- 視訊已上傳的大小值start(第一次是根據JS端認證的填寫,第二次是根據上一次返回的填寫)、分割的視訊流傳輸到upUrl
- 返回json的引數:
- success:驗證上傳該段視訊流是否成功
- start:已上傳的大小
外掛配置解析
HTML部分
首先準備dom結構,包含存放檔案資訊的容器、選擇按鈕和上傳按鈕三個部分。
<!--視訊列表顯示-->
<ul class="resources_body_modal_add_list">
{#list queuedList as item}
<li class="resources_body_modal_add_list_item">
<div class="resources_body_modal_add_list_item_hd" style="background-image: url({item.gvdPic})"></div>
<div class="resources_body_modal_add_list_item_bd">
<input type="text" name="" placeholder="此處為視訊名稱,點選可修改" class="form-control" value={item.name} on-blur={this.updateName(item_index, $event)} />
</div>
<span class="resources_body_modal_add_list_item_icon" on-click={this.deleteQueuedFile(item_index)}>x</span>
<div class="resources_body_modal_add_list_item_bar">
<div class="resources_body_modal_add_list_item_bar_progress"></div>
</div>
</li>
{/list}
</ul>
<!--檔案上傳按鈕-->
<div class="resources_body_modal_add_field">
<div class="resources_body_modal_add_field_cell">
<!--配置所用id-->
<div id="filePicker" class="resources_body_modal_add_field_cell_icon" r-hide={queuedList.length == queuedLimit}>+</div>
<p class="g-mb20" r-hide={queuedList.length == queuedLimit}>點選上傳視訊</p>
<p r-hide={queuedList.length} class="js-empty">每次最多上傳{queuedLimit}個,單個視訊不超過4G</p>
<p r-hide={!queuedList.length} class="js-full">
已選擇
<span class="js-uploadLength"></span>個,
<span class="js-uploadLeft"></span>
</p>
</div>
</div>
複製程式碼
初始化webuploader
uploader = WebUploader.create({
resize: false, // 不壓縮image
swf: base_URL + `jslib/WebUploader/Uploader.swf`, // swf檔案路徑
method: "post",
sendAsBinary : true,//檔案上傳二進位制流
fileNumLimit: 10,//驗證檔案總數量, 超出則不允許加入佇列
fileSingleSizeLimit: 4*1024*1024*1024,//驗證單個檔案大小是否超出限制, 超出則不允許加入佇列
server: upload_URL,// 檔案接收服務端
pick: {
id: `#filePicker`, //這個id是你要點選上傳檔案按鈕的外層div的id
multiple : true //是否可以批量上傳,true可以同時選擇多個檔案
},
chunked: true,//是否要分片處理大檔案上傳
threads: true, //上傳併發數
chunkSize:3*1024*1024, //分片上傳,每片2M,預設是5M
prepareNextFile: true,//上傳當前分片時預處理下一分片
//auto: false //選擇檔案後是否自動上傳
chunkRetry : 1, //如果某個分片由於網路問題出錯,允許自動重傳次數
duplicate: false, //重複選擇
// runtimeOrder: `html5, flash`
accept: {
extensions: `avi,wmv,rm,rmvb,mov,mkv,flv,mp4,f4v,3gp,ts,wma,wav,aac`,
mimeTypes: `.avi,.wmv,.rm,.rmvb,.mov,.mkv,.flv,.mp4,.f4v,.3gp,.ts,.wma,.wav,.aac`
}//視訊檔案字尾
});
複製程式碼
監聽分塊上傳過程中的三個時間點
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile",
"before-send":"beforeSend",
"after-send-file":"afterSendFile",
},{
//時間點1:所有分塊進行上傳之前呼叫此函式
beforeSendFile:function(file){
var deferred = WebUploader.Deferred();
//1、計算檔案的唯一標記,用於斷點續傳
(new WebUploader.Uploader()).md5File(file,0,2*1024*1024)
.progress(function(percentage){
})
.then(function(val){
fileMd5=val;
//獲取檔案資訊後進入下一步
deferred.resolve();
});
return deferred.promise();
},
//時間點2:如果有分塊上傳,則每個分塊上傳之前呼叫此函式
beforeSend:function(block){
var deferred = WebUploader.Deferred();
if(videoAdd[block.file.id] > block.start){
// 分塊存在,跳過
deferred.reject();
}else{
// 分塊不存在或不完整,重新傳送該分塊內容
this.owner.options.formData={
start: block.start,//設定視訊上傳的start點
fileMd5: videoMd5[block.file.id]//設定視訊上傳的唯一標識MD5
}
deferred.resolve();
}
return deferred.promise();
},
//時間點3:所有分塊上傳成功後呼叫此函式
afterSendFile:function(file, response){
//分塊上傳成功,執行成功回撥
successHandler(file, response, fileArr);
}
});
複製程式碼
顯示使用者選擇
監聽fileQueued事件來實現
uploader.on( `fileQueued`, function( file ) {
// 符合條件的視訊才會加進佇列,包括大小,字尾,數量限制
//設定檔案loading狀態
uploader.md5File(file)
// 及時顯示進度
.progress(function(percentage) {
//可根據percentage顯示獲取檔案資訊時的進度
})
//完成
.then(function(md5Val){
//開始執行上傳操作
})
})
複製程式碼
顯示檔案上傳進度
//顯示檔案上傳進度
uploader.on( `uploadProgress`, function(file, percentage) {
var $uploading= $(`.js-uploading-`+file.id);
var progressWid= (percentage*100)+`%`;
$uploading.find(`.js-bar`).width(progressWid);
});
複製程式碼
檔案上傳失敗處理
//檔案上傳失敗處理
uploader.on( `uploadError`, function(file, reason) {
$(`.js-uploading-`+file.id).addClass(`hidden`);
uploader.cancelFile(file);//清空佇列佔位
});
複製程式碼
選擇檔案錯誤處理
uploader.on(`error`, errorHandler);
複製程式碼
至此視訊上傳功能,基本能實現。
tips:
- 彈出窗顯示上傳按鈕功能時,需注意初始化的時間以及銷燬 webuploader 例項,應當在modal顯示後,以及隱藏後回撥處理。
- 當實現多選檔案上傳時,需匹配好上傳分塊時的引數
- IE8瀏覽器彈窗顯示檔案選擇按鈕可能會出現flash錯誤問題,只需在彈窗顯示完全時,用樣式調整即可