上傳功能實現

一、利用Form表單

特點:兼容性最好,但實現起來有點麻煩。

iframe的作用是禁止表單提交默認的網頁刷新,起到局部刷新的作用。

<form action="/upload/img" enctype="multipart/form-data" target="multipartFrame">
    <input id="file-input" type="file" />上傳
    <input class="J-submit" type="submit" value="上傳"/>
</form>
<iframe style="display: none;" name="multipartFrame"></iframe>
$(".submit").on("click", function() {
  const multipartFrame = $('iframe[name="multipartFrame"]');
  if (multipartFrame.length) {
    let tIframe = multipartFrame[0].contentWindow;
    tIframe.message = '';
    tIframe.statusCode = '';
  }

  // 這裏是對上傳的內容做判斷處理,如果 return false,就不會觸發 submit 默認的提交事件
  if (!$(".file-input").val()) {
    console.log("無內容");
    return false;
  }
});

// iframe元素首次加載和接收到響應時會觸發,響應結果會顯示在iframe裏,如果請求失敗了的話,iframe裏的內容就爲空
$('iframe[name="multipartFrame"]').on("load", function() {
  let iframeDom = this.contentDocument
    ? this.contentDocument
    : window.frames[this.name].document;

  if (iframeDom.readyState === "complete") {
    let responseText = iframeDom.body.textContent;
    if (!responseText) {
      return false;
    }
    // 響應結果
    let json = JSON.parse(responseText) || {};
    // 然後對響應結果做業務處理
  }
});

二、使用 FormData

就是平時用的 post 請求,Content-Type默認就是: multipart/form-data; 。

示例:

<input id="file-input" type="file"/>
<a class="J-upload">上傳</a>
// 預覽
$("#file-input").on("change", function() {
  let fileReader = new FileReader(),
    fileType = this.files[0].type;
  fileReader.onload = function() {
    if (/^image/.test(fileType)) {
      $(`<img src="${this.result}">`).appendTo("body");
    }
  };
  fileReader.readAsDataURL(this.files[0]);
});

// 上傳
$(".J-upload").on("click", function() {
  let formData = new FormData(),
    input = $("#file-input")[0];
  if(!input.files.length){
    return alert('請選擇文件');
  }
  formData.append("img", input.files[0]);
  fetch("/uploadImg", {
    method: "POST",
    body: formData
  }).then();
});

三、多文件上傳

多文件上傳就是在 file 標籤添加 multiple 屬性。

//設置 multiple屬性
<input id="file-input" type="file" multiple />
<a class="J-upload">上傳</a>
$(".J-upload").on("click", function() {
  let formData = new FormData(),
    input = $("#file-input")[0];
  if(!input.files.length){
    return alert('請選擇文件');
  }
  //多文件上傳需要遍歷添加到 fromdata 對象
  for(var i = 0; i < input.files.length; i++){
    formData.append('img', input.files[i]);
  }
  fetch("/uploadImg", {
    method: "POST",
    body: formData
  }).then();
});

四、上傳進度條

使用iframe沒法獲取上傳進度,但XHR2的 xhr.upload.onprogress 可以實現上傳進度條。

注意:xhr.upload.onprogress要寫在xhr.send方法前面,否則event.lengthComputable狀態不會改變,只有在最後一次才能獲得,也就是100%的時候

<div>
  選擇文件(可多選): 
  <input type="file" id="f1" multiple/>
  <!-- 進度條 -->
  <div id="progress">
    <span class="red"></span>
  </div>
  <button type="button" id="btn-submit">上 傳</button>
</div>
function submitUpload() {
    var progressSpan = document.querySelector('#progress > span');
    var fileList = document.getElementById('f1').files;
    progressSpan.style.width='0';
    progressSpan.classList.remove('green');

    if(!fileList.length){
      return alert('請選擇文件');
    }

    var fd = new FormData();
    for(var i =0; i<fileList.length; i++){
        fd.append('f1', fileList[i]);
    }

    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://10.70.65.235:8100/', true);
    xhr.onreadystatechange = function () {
        if (xhr.status == 200 &&  xhr.readyState == 4) {
            var obj = JSON.parse(xhr.responseText);
            if(obj.fileUrl.length){
                //alert('上傳成功');
            }
        }
    }
    xhr.onprogress=updateProgress;
    xhr.upload.onprogress = updateProgress;
    function updateProgress(event) {
        if (event.lengthComputable) {
            // 當前上傳進度的百分比
            var completedPercent = (event.loaded / event.total * 100).toFixed(2);
            progressSpan.style.width= completedPercent+'%';
            progressSpan.innerHTML=completedPercent+'%';
            if(completedPercent > 90){ //進度條變色
                progressSpan.classList.add('green');
            }
        }
    }
    xhr.send(fd);
}
//綁定提交事件
document.getElementById('btn-submit').addEventListener('click',submitUpload);

五、拖拽上傳

<div class="img-container">
    drop your image here
</div>
$(".img-container").on("dragover", function (event) {
  // 拖拽圖片的時候dragover和drop事件裏的默認效果一定要禁掉,不然會變成網頁裏打開圖片的效果
  event.preventDefault();
}).on("drop", function(event) {
  event.preventDefault();
  let file = event.originalEvent.dataTransfer.files[0];
  console.log({file})
  // 然後就跟處理input獲取到的file一樣了
});

六、在編輯框裏粘貼上傳

粘貼的方式,通常是在一個編輯框裏操作,如把div的contenteditable設置爲true: 

 <div id="editor" contenteditable="true">
      hello, paste your image here
 </div>
$("#editor").on("paste", function(event) {
    let file = event.originalEvent.clipboardData.files[0];
});

但是Safari的粘貼不是通過event傳遞的,它是直接在輸入框裏面添加一張圖片,它新建了一個img標籤,並把img的src指向一個blob的本地數據。

$("#editor").on("paste", function(event) {
    // 需要setTimeout 0等圖片出來了再處理
    setTimeout(() => {
        let img = $(this).find("img[src^='blob']")[0];
        console.log(img.src);
    }, 0);
});

七、大文件上傳

切片上傳,斷點續傳。

詳情

八、參考文章

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章