日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

vue前端上传文件夹的插件_基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件...

發布時間:2025/4/5 vue 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vue前端上传文件夹的插件_基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 前言

之前公司要在管理系統中做一個全局上傳插件,即切換各個頁面的時候,上傳界面還在并且上傳不會受到影響,這在vue這種spa框架面前并不是什么難題。然而后端大佬說我們要實現分片上傳、秒傳以及斷點續傳的功能,聽起來頭都大了。

很久之前我寫了一篇webuploader的文章,結果使用起來發現問題很多,且官方團隊不再維護這個插件了, 經過多天調研及踩雷,最終決定基于vue-simple-uploader插件實現該功能,在項目中使用起來無痛且穩定。

如果你只是想實現基本的(非定制化的)上傳功能,直接使用vue-simple-uploader,多讀一下它的文檔,不需要更多的二次封裝。

如果你只是想實現全局上傳插件,也可以參照一下我的實現。

如果你用到了分片上傳、秒傳及斷點續傳這些復雜的功能,恭喜你,這篇文章的重點就在于此。

2. 關于vue-simple-uploader

vue-simple-uploader是基于 simple-uploader.js 封裝的vue上傳插件。它的優點包括且不限于以下幾種:

支持文件、多文件、文件夾上傳;支持拖拽文件、文件夾上傳

可暫停、繼續上傳

錯誤處理

支持“秒傳”,通過文件判斷服務端是否已存在從而實現“秒傳”

分塊上傳

支持進度、預估剩余時間、出錯自動重試、重傳等操作

讀這篇文章之前,建議先讀一遍simple-uploader.js的文檔,然后再讀一下vue-simple-uploader的文檔,了解一下各個參數的作用是什么,我在這里假定大家已經比較熟悉了。。

vue-simple-uploader文檔

安裝:npm install vue-simple-uploader --save

使用:在main.js中:

import uploader from 'vue-simple-uploader'

Vue.use(uploader)

3. 基于vue-simple-uploader封裝全局上傳組件

引入vue-simple-uploader后,我們開始封裝全局的上傳組件globalUploader.vue,代碼比較長,就不整個放出來了,源碼放到github上了,這里一步一步地講解。

template部分如下,本人自定義了模板和樣式,所以html部分比較長,css部分暫時不列出,大家可以根據自己的ui去更改,主要關注一下uploader這個組件的options參數及文件added、success、progress、error幾個事件:

ref="uploader"

:options="options"

:autoStart="false"

@file-added="onFileAdded"

@file-success="onFileSuccess"

@file-progress="onFileProgress"

@file-error="onFileError"

class="uploader-app">

選擇文件

文件列表

  • 暫無待上傳文件

組件中的data部分:

data() {

return {

options: {

target: 'http://xxxxx/xx', // 目標上傳 URL

chunkSize: '2048000', //分塊大小

fileParameterName: 'file', //上傳文件時文件的參數名,默認file

maxChunkRetries: 3, //最大自動失敗重試上傳次數

testChunks: true, //是否開啟服務器分片校驗

// 服務器分片校驗函數,秒傳及斷點續傳基礎

checkChunkUploadedByResponse: function (chunk, message) {

let objMessage = JSON.parse(message);

if (objMessage.skipUpload) {

return true;

}

return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0

},

headers: {

// 在header中添加的驗證,請根據實際業務來

Authorization: "Bearer " + Ticket.get().access_token

},

},

attrs: {

// 接受的文件類型,形如['.png', '.jpg', '.jpeg', '.gif', '.bmp'...] 這里我封裝了一下

accept: ACCEPT_CONFIG.getAll()

},

panelShow: false, //選擇文件后,展示上傳panel

}

},

全局引用:

在app.vue中引用,即作為全局的組件一直存在,只不過在不使用的時候把上傳界面隱藏了

4. 文件上傳流程概覽

1. 點擊按鈕,觸發文件上傳操作:

(如果你做的不是全局上傳的功能,而是直接點擊上傳,忽略這一步。)

因為我做的是全局上傳的插件,要先把上傳的窗口隱藏起來,在點擊某個上傳按鈕的時候,用Bus發送一個openUploader的事件,在globalUploader.vue中接收該事件,trigger我們uploader-btn的click事件。

在某個頁面中,點擊上傳按鈕,同時把要給后臺的參數帶過來(如果有的話),這里組件之間傳值我用的event bus,當然用vuex會更好:

Bus.$emit('openUploader', {

superiorID: this.superiorID

})

在globalUploader.vue中接收該事件:

Bus.$on('openUploader', query => {

this.params = query || {};

if (this.$refs.uploadBtn) {

// 這樣就打開了選擇文件的操作窗口

$('#global-uploader-btn').click();

}

});

2. 選擇文件后,將上傳的窗口展示出來,開始md5的計算工作

onFileAdded(file) {

this.panelShow = true;

// 計算MD5,下文會提到

this.computeMD5(file);

},

這里有個前提,我在uploader中將autoStart設為了false,為什么要這么做?

在選擇文件之后,我要計算MD5,以此來實現斷點續傳及秒傳的功能,所以選擇文件后直接開始上傳肯定不行,要等MD5計算完畢之后,再開始文件上傳的操作。

具體的MD5計算方法,會在下面講,這里先簡單引出。

上傳過程中,會不斷觸發file-progress上傳進度的回調

// 文件進度的回調

onFileProgress(rootFile, file, chunk) {

console.log(`上傳中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`)

},

3. 文件上傳成功后

文件上傳成功后,在“上傳完成”的回調中,通過服務端返回的needMerge字段,來判斷是否需要再發送合并分片的請求,

如果這個字段為true,則需要給后臺發一個請求合并的ajax請求,否則直接上傳成功。

注意:這里的needMerge是我和后臺商議決定的字段名

onFileSuccess(rootFile, file, response, chunk) {

let res = JSON.parse(response);

// 服務器自定義的錯誤,這種錯誤是Uploader無法攔截的

if (!res.result) {

this.$message({ message: res.message, type: 'error' });

return

}

// 如果服務端返回需要合并

if (res.needMerge) {

api.mergeSimpleUpload({

tempName: res.tempName,

fileName: file.name,

...this.params,

}).then(data => {

// 文件合并成功

Bus.$emit('fileSuccess', data);

}).catch(e => {});

// 不需要合并

} else {

Bus.$emit('fileSuccess', res);

console.log('上傳成功');

}

},

onFileError(rootFile, file, response, chunk) {

console.log(error)

},

5. 文件分片

vue-simple-uploader自動將文件進行分片,在options的chunkSize中可以設置每個分片的大小。

如圖:對于大文件來說,會發送多個請求,在設置testChunks為true后(在插件中默認就是true),會發送與服務器進行分片校驗的請求,下面的第一個get請求就是該請求;后面的每一個post請求都是上傳分片的請求

看一下發送給服務端的參數,其中chunkNumber表示當前是第幾個分片,totalChunks代表所有的分片數,這兩個參數都是都是插件根據你設置的chunkSize來計算的。

需要注意的就是在最后文件上傳成功的事件中,通過后臺返回的字段,來判斷是否要再給后臺發送一個文件合并的請求。

6. MD5的計算過程

斷點續傳及秒傳的基礎是要計算文件的MD5,這是文件的唯一標識,然后服務器根據MD5進行判斷,是進行秒傳還是斷點續傳。

在file-added事件之后,就計算MD5,我們最終的目的是將計算出來的MD5加到參數里傳給后臺,然后繼續文件上傳的操作,詳細的思路步驟是:

把uploader組件的autoStart設為false,即選擇文件后不會自動開始上傳

先通過 file.pause()暫停文件,然后通過H5的FileReader接口讀取文件

將異步讀取文件的結果進行MD5,這里我用的加密工具是spark-md5,你可以通過npm install spark-md5 --save來安裝,也可以使用其他MD5加密工具。

file有個屬性是uniqueIdentifier,代表文件唯一標示,我們把計算出來的MD5賦值給這個屬性 file.uniqueIdentifier = md5,這就實現了我們最終的目的。

通過file.resume()開始/繼續文件上傳。

/**

* 計算md5,實現斷點續傳及秒傳

* @param file

*/

/**

* 計算md5,實現斷點續傳及秒傳

* @param file

*/

computeMD5(file) {

let fileReader = new FileReader();

let time = new Date().getTime();

let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;

let currentChunk = 0;

const chunkSize = 10 * 1024 * 1000;

let chunks = Math.ceil(file.size / chunkSize);

let spark = new SparkMD5.ArrayBuffer();

// 文件狀態設為"計算MD5"

this.statusSet(file.id, 'md5');

file.pause();

loadNext();

fileReader.onload = (e => {

spark.append(e.target.result);

if (currentChunk < chunks) {

currentChunk++;

loadNext();

// 實時展示MD5的計算進度

this.$nextTick(() => {

$(`.myStatus_${file.id}`).text('校驗MD5 '+ ((currentChunk/chunks)*100).toFixed(0)+'%')

})

} else {

let md5 = spark.end();

this.computeMD5Success(md5, file);

console.log(`MD5計算完畢:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用時:${new Date().getTime() - time} ms`);

}

});

fileReader.onerror = function () {

this.error(`文件${file.name}讀取出錯,請檢查該文件`)

file.cancel();

};

function loadNext() {

let start = currentChunk * chunkSize;

let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));

}

},

computeMD5Success(md5, file) {

// 將自定義參數直接加載uploader實例的opts上

Object.assign(this.uploader.opts, {

query: {

...this.params,

}

})

file.uniqueIdentifier = md5;

file.resume();

this.statusRemove(file.id);

},

給file的uniqueIdentifier 屬性賦值后,請求中的identifier即是我們計算出來的MD5

7. 秒傳及斷點續傳

在計算完MD5后,我們就能談斷點續傳及秒傳的概念了。

服務器根據前端傳過來的MD5去判斷是否可以進行秒傳或斷點續傳:

a. 服務器發現文件已經完全上傳成功,則直接返回秒傳的標識。

b. 服務器發現文件上傳過分片信息,則返回這些分片信息,告訴前端繼續上傳,即斷點續傳。

7.1 對于前端來說

在每次上傳過程的最開始,vue-simple-uploader會發送一個get請求,來問服務器我哪些分片已經上傳過了,

這個請求返回的結果也有幾種可能:

a. 如果是秒傳,在請求結果中會有相應的標識,比如我這里是skipUpload為true,且返回了url,代表服務器告訴我們這個文件已經有了,我直接把url給你,你不用再傳了,這就是秒傳。

圖a1:秒傳情況下后臺返回值

圖a2:秒傳gif

b. 如果后臺返回了分片信息,這是斷點續傳。如圖,返回的數據中有個uploaded的字段,代表這些分片是已經上傳過的了,插件會自動跳過這些分片的上傳。

圖b1:斷點續傳情況下后臺返回值

圖b2:斷點續傳gif

c. 可能什么都不會返回,那這就是個全新的文件了,走完整的分片上傳邏輯

7.2 前端做分片檢驗:checkChunkUploadedByResponse

前面講的是概念,現在說一說前端在拿到這些返回值之后怎么處理。

插件自己是不會判斷哪個需要跳過的,在代碼中由options中的checkChunkUploadedByResponse控制,它會根據 XHR 響應內容檢測每個塊是否上傳成功了,成功的分片直接跳過上傳

你要在這個函數中進行處理,可以跳過的情況下返回true即可。

checkChunkUploadedByResponse: function (chunk, message) {

let objMessage = JSON.parse(message);

if (objMessage.skipUpload) {

return true;

}

return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0

},

注:skipUpload 和 uploaded 是我和后臺商議的字段,你要按照后臺實際返回的字段名來。

8. 源碼及后記

總共幾個文件,app.vue,封裝的全局上傳組件globalUploader.vue,調用組件的demo.vue,源碼放到github上了:https://github.com/shady-xia/Blog/tree/master/vue-simple-uploader。

globalUploader源碼中的ticket和api都是自己用的, 一個是accesstoken,一個是基于axios封裝的請求庫,請根據你的業務需求替代之。另外上傳界面的展開和收起用到了jquery,通知用到了Element的組件,請忽略之。

本人水平有限,更多的是提供一個思路,供大家參考。

封裝完這個插件后,再加上開發文件資源庫,我發現已經基本實現了一個簡易的百度網盤了,一個管理系統,功能搞的這么復雜,坑爹啊!

8.1 關于第一個分片丟失問題

關于開啟了testChunk后服務器收不到第一個分片的問題:

simpleUploader文檔上是這么寫的:

testChunk的那個get請求,默認帶了第一個分片給服務端,如果服務端返回的是200狀態,則假定當前塊已經上傳過了,不會再上傳了;

所以這里服務器要改成其他http狀態碼,比如204,這樣就不在“ 200, 201, 202”這個集合里了,代表服務端還沒有這個塊,需要按照標準模式上傳,這樣第一個分片就會再次被上傳了

2019/8/6更新

1、優化了計算文件MD5的方式,展示MD5的計算進度

之前文章中計算MD5的方式為對整個文件直接計算MD5,很吃內存,容易導致瀏覽器崩潰

我改成了通過分片讀取文件的方式計算MD5,防止直接讀取大文件時因內存占用過大導致的網頁卡頓、崩潰

2、新增了的自定義的狀態

(之前我就封裝了幾種自定義狀態,最近總有小伙伴問怎么沒有“校驗MD5”,“合并中”這些狀態,我就把我的方法寫出來了,方式很笨,但是能實現效果)

插件原本只支持了success、error、uploading、paused、waiting這幾種狀態,

由于業務需求,我額外增加了“校驗MD5”、“合并中”、“轉碼中”、“上傳失敗”這幾種自定義的狀態

由于前幾種狀態是插件已經封裝好的,我不能改源碼,只能用比較hack的方式:

當自定義狀態開始時,要手動調一下statusSet方法,生成一個p標簽蓋在原本的狀態上面;當自定義狀態結束時,還要手動調用statusRemove移除該標簽。

this.statusSet(file.id, 'merging');

this.statusRemove(file.id);

具體使用可以參考源碼,同時希望simple-uploader的插件作者后面能夠支持自定義狀態的配置。

總結

以上是生活随笔為你收集整理的vue前端上传文件夹的插件_基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。