之前有一個案子的使用者有一個特別的要求,因為在網頁上瀏覽的圖片大小稍微大了一點,在行動裝置上網路不穩定的時候,會載入比較久的時間,所以使用者就想說能不能在圖片顯示前,先顯示一個 Loading 的畫面,等待圖片下載完成之後再顯示出來?
一般來說,網頁要顯示圖片,通常就是指定 <img> 的 src 屬性值就可以了,但是要滿足前述使用者所提出的要求,我們就得在背景等待圖片下載完成,才將圖片顯示出來,所以我打算用 CSS 來顯示 Loading 效果,用 jQuery 的 $.ajax() 非同步下載圖片,圖片下載完成後,關閉 CSS Loading 效果,然後將下載下來的二進位圖片檔塞進 <img> 的 src 顯示出來。
CSS Loading 效果
由於我對 CSS 只停留在新手村的程度,所以 CSS Loading 效果我只有能力找網路上現成的來用,https://tobiasahlin.com/spinkit/ 這個網頁收錄幾種 CSS Loading 效果,我挑其中一個來用。
<!-- HTML -->
<div class="spinner"></div>
<!-- CSS -->
.spinner {
width: 40px;
height: 40px;
background-color: #333;
margin: 100px auto;
-webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;
animation: sk-rotateplane 1.2s infinite ease-in-out;
}
@@-webkit-keyframes sk-rotateplane {
0% { -webkit-transform: perspective(120px) }
50% { -webkit-transform: perspective(120px) rotateY(180deg) }
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }
}
@@keyframes sk-rotateplane {
0% {
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)
} 50% {
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)
} 100% {
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
$.ajax() 下載圖片
如果我們直接用 $.ajax() 發送 HTTP Request 去 GET 一張圖片,是無法取得正確結果的,我們會收到一堆亂碼,原因是因為 $.ajax() 預設沒有針對二進位資料進行相應的處理,一律視為文字資料。
那該怎麼辦? 我們要了解 $.ajax() 其實是 XMLHttpRequest 的封裝,而 XMLHttpRequest 回傳的資料類型是由 responseType
這個屬性來決定的,預設值是空字串,等同於是 text
,我們只要將其值改為 blob
,收到的回傳結果就會是 Blob 物件。
想知道 XMLHttpRequest 的 responseType 還支援哪些資料類型,可以參考 MDN 的說明。
要在 $.ajax() 調整 XMLHttpRequest 的 responseType 屬性值,必須在 xhrFields
設定裡面,指定 responseType 的值。
接下來事情就變得簡單了,只剩下將圖片的 Blob 物件塞給 <img> 的 src 屬性就搞定了,我這邊選用 Data URL 的方式,使用 FileReader 的 readAsDataURL() 方法來處理。
另一種方式是使用 Object URL 來處理,也是可以的。
下載其他二進位資料
我們下載的二進位資料是圖片的話,有 <img> 可以將其顯示出來,但是如果我們下載的二進位資料是 .pdf、.docx、.xlsx、...等非圖片的資料,一般處理的方式是另存新檔,下面我們就來撰寫用 $.ajax() 將二進位資料下載下來之後,觸發彈跳出另存新檔視窗的程式碼。
我們利用點擊超連結觸發另存新檔的方式來做,關鍵的地方在於超連結需要指定 download
屬性值,給它一個另存新檔的檔案名稱。
同場加映
如果我們很不幸運,遇到一個菜鳥後端工程師,用 text/plain
傳 JSON 物件到前端給我們,調整 XMLHttpRequest 的 responseType 為 json
,也可以解決資料類型不對的問題。
在我剛學習網頁程式設計的那個年代,還沒有 XMLHttpRequest,網頁的互動也比較死板一點,跟現在差很多,在未來 HTML 的 Web APIs 勢必會日臻豐富,有一個網站 WHAT WEB CAN DO TODAY? 收錄了到目前為止,我們可以在 Web 應用程式上做到的事情,每一個 Feature 點進去還提供了範例程式碼,這都是在過去很難想像的,以上用 jQuery 的 $.ajax() 下載二進位資料的方式分享給大家,順道也分享一些額外的資訊,希望對大家有一點幫助。