首頁 > 軟體

js前端上傳檔案縮圖技巧範例詳解

2023-03-27 06:01:08

引言

通常情況下,前端提交給伺服器的資料格式為JSON格式,但很多時候使用者想上傳自己的頭像、視訊等,這些非文字資料的時候,就不能直接以JSON格式上傳到後端了。

當我們要獲取使用者上傳的檔案,可以使用input表單項,將type屬性值設定為“file”。

<form action="">
    <input type="file" name="file">
</form>

同時,我們為表單項繫結change事件,當用戶上傳檔案時,我們就可以在事件物件中獲取到使用者上傳的檔案。

<script>
    const inp = document.querySelector("input")
    inp.onchange = function(e) {
      console.log(e.target.files);
    }
</script>

但需要注意的是 e.target.files 是一個類陣列(FileList),會將你上傳的多個檔案都儲存在這個陣列中,而這個例子中我們只上傳一個檔案,所以我們用 e.target.files[0] 將這個檔案物件取出來。(若想上傳多個檔案,可以在input標籤中增加multiple屬性)。

檔案物件簡介

在學習上傳檔案前,我們先簡單瞭解四個與檔案相關的內建物件。

Blob

Blob是一個儲存二進位制的物件,實際上很少直接使用這個物件。

  • size 屬性,返回Blob物件的位元組數,即檔案的大小。
const input = document.getElementById('input');
const output = document.getElementById('output');
input.addEventListener('change', (e) => {
output.innerText = `檔案的大小為${e.target.files[0].size}`;
});
  • slice() 方法,對Blob物件進行切片,返回新的Blob物件。
  • 可以用這個方法實現大檔案切片上傳。
var blob = new Blob().slice([start [, end [, contentType]]]};
/*
- start 開始位置的下標
- end 結束位置的下標
- contentType 給新的Blob賦予一個新的檔案型別。這將會把它的 type 屬性設為被傳入的值。它的預設值是一個空的字串
*/

File

  • 通常情況下, File 物件是來自使用者在一個 <input> 元素上選擇檔案後返回的 FileList 物件,也可以是來自由拖放操作生成的 DataTransfer 物件。
  • file 物件是Blob的一個子類,因此file物件可以直接使用Blob中的方法和屬性。
const input = document.getElementById('input');
input.addEventListener('change', (e) => {
  let file = e.target.files[0]
  if(file.size > 4 * 1024 * 1024 || file.type != "image/jpeg"){
      alert("檔案不得大於4M,且圖片格式要為jpg格式。")
  }
});

FileReader

  • 非同步讀取儲存在使用者計算機上的檔案(或原始資料緩衝區)的內容,使用 File 或 Blob 物件指定要讀取的檔案或資料。
var fr = new FileReader();
  • readAsDataURL(),讀取指定的 Blob 或 File 物件。讀取操作完成的時候,readyState 會變成已完成DONE,並觸發 loadend 事件,同時 result 屬性將包含一個data:URL 格式的字串(base64 編碼)以表示所讀取檔案的內容。
fr.readAsDataURL(blob)
/*
- blob,被讀取的 blob 或 file物件
*/
  • readAsText(),將 Blob 或者 File 物件根據特殊的編碼格式轉化為內容 (字串形式)。
fr.readAsDataURL(blob)
/*
- blob,被讀取的 blob 或 file物件
*/

注意,以上兩個方法都是非同步的,也就是說,只有當執行完成後才能夠檢視到結果,如果直接檢視是無結果的,並返回 undefined。我們需要為fr掛載load或loadend事件,在事件回撥中使用result屬性才能獲取結果。

<input type="file" onchange="previewFile()">
<img src="" height="200">
<script>
function previewFile(e) {
  var img = document.querySelector('img');
  let file = e.target.files[0];
  let fr = new FileReader();
  reader.readAsDataURL(file);
  fr.addEventListener("load", function () {
    img.src = fr.result;
  });
}
</script>

FormData

  • 提供了一種表示表單資料的鍵值對 key/value 的構造方式。
  • <form>標籤中,我們直接點選提交按鈕,瀏覽器會以預設以x-www-form-urlencoded的資料格式向伺服器提交資料。
  • 當我們為form標籤設定enctype屬性時,可以設定傳送的資料格式。
<!-- 
application/x-www-form-urlencoded 在傳送前編碼所有字元(預設)
multipart/form-data  不對字元編碼。在使用包含檔案上傳控制元件的表單時,必須使用該值
text/plain           空格轉換為 "+" 加號,但不對特殊字元編碼。
-->
<form action="/upload" enctype="multipart/form-data" method="post">
    <input type="text" name="username">
    <input type="password" name="password">
    <input type="file" name="file">
    <input type="submit">
</form>

在上面的例子中,瀏覽器會以formdata的資料格式向伺服器傳送表單資料,但我們使用框架來編寫業務時,我們不會直接使用表單提交資料,通常都是將表單中的資料提取出來,手動構建出相應的資料格式,再用aixos傳送給伺服器,所以我們需要主動使用FormData物件封裝file物件

  • append() 方法,向 FormData 中新增新的屬性值,FormData 對應的屬性值存在也不會覆蓋原值,而是新增一個值,如果屬性不存在則新增一項屬性值。
function previewFile(e) {
    const formdata = new FormData()
    formData.append("userAvatar", e.target.files[0]);
}
/*
    第一個值為檔名稱,第二個值為要傳送的檔案物件/字串
*/

檔案物件之間的關係

  • 由上圖可以看出,當我們通過input標籤上傳檔案時,我們可以得到一個file物件,file物件與blob物件可以互相轉換,但要將檔案物件上傳給伺服器則是不允許的,因為後端無法識別這種物件,因此我們需要將檔案物件包裝成formdata物件,或者轉換為base64等文字格式再傳給後端。
function previewFile(e) {
  let file = e.target.files[0];
  let formdata = new FormData()
  formdata.append("userAva", file)    // 注意,若要實現大檔案分片上傳時,同一個檔案分片的檔名要相同,方便後端拼接
  axios.post("http://localhost/...", {
      data: formdata
  }).then( res => {
      console.log(res)
  )
}

縮圖的實現

我們通過input標籤上傳圖片後,使用者無法檢視所提交的圖片。

因此為了提高使用者體驗,我們在使用者提交圖片後,將圖片在頁面中顯示出來。

<form action="">
  <input type="file" name="file"><br/>
  <img src="" alt="">
</form>
<script>
  const inp = document.querySelector("input")
  const img = document.querySelector("img")
  const fr = new FileReader()
  inp.onchange = function(e) {
    let file = e.target.files[0]
    fr.readAsDataURL(file)
  }
  fr.onload = function() {
    img.src = fr.result
  }
</script>

未提交前

提交後

總結

  • 前端上傳檔案時需要使用FormData物件對檔案進行包裝後才能傳給伺服器。
  • 獲取使用者上傳的圖片後,使用FileReader物件中提供的readAsDataUrl()方法,將圖片轉化為base64格式,再將base64編碼讓img標籤載入,實現縮圖的效果。

以上就是js前端上傳檔案縮圖技巧範例詳解的詳細內容,更多關於js前端上傳檔案縮圖的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com