上传文件显示进度条_文件上传带进度条进阶-断点续传
生活随笔
收集整理的這篇文章主要介紹了
上传文件显示进度条_文件上传带进度条进阶-断点续传
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
說明
1. 把文件按大小1M分割成N份
2. 每次上傳時,告訴后臺大文件的md5、當前第幾份(從0開始)、總共幾份
3. 并行上傳,前端同時開啟5個請求進行傳輸增加速度
4. 上傳失敗或出錯后,繼續上傳下一份,把出錯的份放在隊尾,如果一直出錯則中斷請求防止死循環
5. 后臺接受文件后通過md5進行比對,上次是否接受過此文件,如果接受則跳過,最后進行文件合并出來
6. 前端代碼如下...
7. 查看源代碼請點擊在線演示地址
先上html
<input id="fileInput" type="file" multiple="multiple" name="" /><ul id="box"><!-- <li><span>文件名</span><span>文件類型</span><span>文件大小</span><span>上傳進度</span><span>總進度</span><span>操作</span></li><li><span></span><span></span><span></span><span><i><em></em></i><i><em></em></i><i><em></em></i><i><em></em></i><i><em></em></i></span><span><i><em></em></i></span><span><a href="javascript:;">上傳</a><a href="javascript:;">暫停</a><a href="javascript:;">刪除</a></span></li> --> </ul>選擇input時把文件信息寫在頁面上,因為涉及到斷點續傳,為保證文件的唯一性,需要本地讀取文件并對其進行md5
fileInput.addEventListener('change', function() {var files = this.files;if (files.length) {let str = '<li><span>文件名</span><span>文件類型</span><span>文件大小</span><span>上傳進度</span><span>總進度</span><span>操作</span></li>';for (var i = 0; i < files.length; i++) {var file = files[i];str += `<li><span>${file.name}</span><span>${file.type}</span><span>${formatByte(file.size)}</span><span><i><em></em></i><i><em></em></i><i><em></em></i><i><em></em></i><i><em></em></i></span><span><i><b>文件讀取中</b></i><i><em></em></i></span><span data-index="${i}"><a data-control="1" href="javascript:;">上傳</a><a data-control="2" href="javascript:;">暫停</a><a data-control="3" href="javascript:;">刪除</a></span></li>`;}box.innerHTML = str;readFilesStep(0); // 文件太大,同步讀取} else {box.innerHTML = ''} }, false);同步讀取文件操作
function readFilesStep(i) {var files = fileInput.files;if (!files[i]) {return}var oLi = box.children[i + 1];oLi.dataset.count = Math.ceil(files[i].size / SIZE); // 總共多少份var readProgress = oLi.children[4].children[0].children[0];var reader = new FileReader();reader.readAsDataURL(files[i]);reader.onload = function () {oLi.dataset.md5 = md5(this.result);readProgress.innerHTML = '文件讀取完畢';readProgress.parentNode.className = 'stop hide';readFilesStep(i + 1);reader = null;}reader.onerror = function (e) {console.error(e);readProgress.innerHTML = '文件讀取失敗,請重新選擇';readFilesStep(i + 1);reader = null;} }因為li是創建出現的,對box進行事件委托
box.addEventListener('click', function (ev) {var target = ev.target;var control = target.dataset.control;var index = Number(target.parentNode.dataset.index);if (control === "1") {// 上傳uploadItem(index);} else if (control === "2") {// 暫停pauseItem(index);} else if (control === "3") {// 刪除delItem(index);} }, false);上傳代碼如下
var SIZE = 1024 * 1024; // 切片大小 var FETCH_NUM = 5; // 上傳文件同時發起請求數 var FETCH_MAP = {}; // 上傳請求句柄,取消請求用 var FETCH_POOL = {}; // 每一個上傳文件的份數function uploadItem(index) {var file = fileInput.files[index];var oLi = box.children[index + 1];var isPlaying = Number(oLi.dataset.playing) || 0;if (isPlaying) { return }oLi.dataset.playing = 1;var fileMd5 = oLi.dataset.md5;var count = oLi.dataset.count;var lastLoaded = Number(oLi.dataset.lastLoaded || 0);if (!fileMd5) {alert('請等待文件讀取')} else {var maxErrorTimes = 10; // 最大出錯次數// 第一次點開始會進行創建if (!FETCH_POOL[fileMd5]) {FETCH_POOL[fileMd5] = [];for (var i = 0; i < count; i++) {FETCH_POOL[fileMd5][i] = i;}}FETCH_MAP[fileMd5] = [];for (var i = 0; i < FETCH_NUM; i++) {FETCH_MAP[fileMd5][i] = null;step(i)}function step(i) {var cur = FETCH_POOL[fileMd5].shift();if (cur !== undefined) {FETCH_MAP[fileMd5][i] = uploadStep({file: file, cur: cur, count: count, md5: fileMd5,progressCb: function(e) {var loaded = lastLoaded + e.loaded;setProgress(loaded);var progressItem = (e.loaded / e.total * 100).toFixed(2) + '%';var oProgressItem = oLi.children[3].children[i];oProgressItem.title = progressItem;oProgressItem.children[0].style.width = progressItem;if (progressItem === '100.00%') {oProgressItem.className = 'stop'} else {oProgressItem.className = ''}}, successCb: function(){lastLoaded += SIZE;setProgress(lastLoaded, true);step(i);}, errorCb: function(status) {// 失敗把當前份放在末尾,繼續下一步FETCH_POOL[fileMd5].push(cur);if (status === 0) {// 手動取消 暫停} else if (maxErrorTimes--) {// 出錯10次后不再上傳,防止進入死循環step(i);}}});}}function setProgress(loaded, isFinished) {var oProgress = oLi.children[4].children[1];// 實際上傳的數據大小 > 文件大小,此處做修正處理if (loaded > file.size) {if (isFinished) {loaded = file.size;oProgress.className = 'stop';} else {loaded = file.size * 0.9999;}}oLi.children[2].innerHTML = formatByte(loaded) + '/' + formatByte(file.size);var progress = (loaded / file.size * 100).toFixed(2) + '%';var lastProgress = oProgress.title || '0%';// 并行上傳 此處可能是線路1的進度和線路2的進度比較,優先顯示最大值progress = parseFloat(lastProgress) < parseFloat(progress) ? progress : lastProgress;// 總進度條oProgress.title = progress;oProgress.children[0].style.width = progress;if (isFinished) {oLi.dataset.lastLoaded = loaded;}}} }分步上傳代碼
function uploadStep(obj) {var file = obj.file;var cur = obj.cur;var fileMd5 = obj.md5;var count = obj.count;var progressCb = obj.progressCb;var successCb = obj.successCb;var errorCb = obj.errorCb;var params = new FormData();var filename = file.name;var fileChunk = file.slice(SIZE * cur, SIZE * (cur + 1));params.append('md5', fileMd5);params.append('file', fileChunk);params.append('cur', cur);params.append('count', count);var xhr = new XMLHttpRequest();xhr.onreadystatechange = function () {if (xhr.readyState == 4) {if (xhr.status == 200) {successCb && successCb(JSON.parse(xhr.responseText))} else {errorCb && errorCb(xhr.status)}}}xhr.upload.onprogress = function (e) {progressCb && progressCb(e)}xhr.open('POST', '/api/upload', true);xhr.send(params);return xhr; }function formatByte(b) {var kb = b / 1024;if (kb >= 1024) {var m = kb / 1024;if (m >= 1024) {var g = m / 1024;return g.toFixed(2) + 'G';} else {return m.toFixed(2) + 'M';}} else {return kb.toFixed(2) + 'K';} }點擊暫停時,取消上個建立的XMLHttpRequest請求,這里用FETCH_MAP[md5]進行標記
function pauseItem(index) {var file = fileInput.files[index];var oLi = box.children[index + 1];var isPlaying = Number(oLi.dataset.playing) || 0;if (!isPlaying) { return }oLi.dataset.playing = 0;var fileMd5 = oLi.dataset.md5;for (var i = 0; i < FETCH_MAP[fileMd5].length; i++) {if (FETCH_MAP[fileMd5][i]) {FETCH_MAP[fileMd5][i].abort();FETCH_MAP[fileMd5][i] = null;}} }點擊刪除時,取消上次請求,并隱藏li
function delItem(index) {var file = fileInput.files[index];var oLi = box.children[index + 1];var fileMd5 = oLi.dataset.md5;oLi.className = 'hide';if (FETCH_MAP[fileMd5]) {for (var i = 0; i < FETCH_MAP[fileMd5].length; i++) {if (FETCH_MAP[fileMd5][i]) {FETCH_MAP[fileMd5][i].abort();FETCH_MAP[fileMd5][i] = null;}}} }效果圖:
https://www.zhihu.com/video/1086059444886044672在線演示地址:上傳大文件
Web Worker 真正的多線程上傳,待更新。。。
總結
以上是生活随笔為你收集整理的上传文件显示进度条_文件上传带进度条进阶-断点续传的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iphone怎么改隔空投送名字
- 下一篇: 沉冤得雪是什么意思 沉冤得雪的解释