Javascript 基礎夯實 —— 通過程式碼構建一個包含檔案的 FormData 物件

weixin_34185560發表於2017-12-10
147516-af361b57e8d94040.png

當我們在寫一個表單提交的時候,填入表單的資料會被自動序列化為一個 FormData 物件,再 post 到後臺介面

我們也經常會碰到上傳檔案或圖片的需求,不管是自己擼還是用第三方庫,最終都是通過一個 <input type="file"> 的標籤來完成檔案的選擇操作,然後還是包裝成了一個 FormData 物件傳送到後臺,但這裡傳送的卻是原始的檔案,而我們往往需要對圖片進行壓縮等操作

由於 FormData 的欄位值的型別只能是字串、File 或 Blob,如果型別不是這三種,就會被自動轉為字串。那我們在對 input 選擇的圖片進行壓縮處理後(本文以圖片為例),又該怎麼將壓縮後的圖片轉為一個可以放進 FormData 的型別呢?

如何向 FormData 新增欄位

const formData = new FormData()

formData.append('name', 'test')

在上面的程式碼中,通過append方法向formData中新增了一個欄位名為'name'的值'test'

append方法也可以接受第三個引數,當型別為 File 或 Blob 時,第三個引數為該檔案的檔名,如果不傳則預設為 'blob'

如果想要刪除某個欄位,則可以用delete方法

需要注意的是,如果在控制檯上列印formData的話,我們是看不到它裡面的具體欄位的,如果想要檢視,則可以通過以下幾個方法:

formData.entries()
該方法會返回一個迭代器,通過迭代器的 next() 方法,會返回每一次迭代到的欄位名與值組成的一個陣列

formData.forEach()
該方法與陣列的 forEach() 使用方法類似,接受一個回撥函式,回撥的第一個引數是當前遍歷到的值,第二個引數為當前遍歷的欄位名

formData.keys()
與 entries() 類似都返回迭代器物件,但是呼叫 next() 後只返回欄位名

formData.values()
與 entries() 類似都返回迭代器物件,但是呼叫 next() 後只返回值

將壓縮後的圖片轉為 Blob 物件

Blob 物件就是二進位制大物件,FormData 中新增的 File 物件最終也是通過二進位制的形式進行傳輸的,所以我們可以直接將圖片轉為 Blob

一般來說前端壓縮圖片都是通過 canvas 進行的,再將 canvas 的內容讀取為一個 base64 的 url,這個 url 在瀏覽器中可以直接顯示一張圖片,所以要將壓縮後的圖片轉為 Blob,其實就是將 base64 的 url 轉為 Blob

function base64Url2Blob (url) {
  // 將base64url通過 , 分割為含有兩個元素的陣列
  const temp = url.split(',')
    // 將圖片的base64編碼資料解碼
  const bytes = window.atob(temp[1])
  // 匹配圖片的 mime
  const mime = temp[0].match(/:(.*?);/)[1]
    // 建立一個型別化陣列,該陣列的長度與解碼後的圖片資料長度相同
  let ia = new Uint8Array(bytes.length)
    // 變數圖片資料的每一位,並將每一位的 Unicode 編碼存入型別化陣列
  for (let i = 0; i < bytes.length; i++) {
    ia[i] = bytes.charCodeAt(i)
  }
    // 通過型別化陣列建立一個 Blob 物件
  return new Blob([ia], {type: mime})
}

通過上面的程式碼就可以將一個經過壓縮的 base64 的圖片轉為 Blob 物件啦,最後再 appendformData 就可以了

formData.append('file', base64Url2Blob(base64Url), 'imageName.png')
147516-77840857f03c6558.jpg
掃碼關注前端週記公眾號

相關文章