AJAX 資料傳輸進度條設計與實現_qingyafan的部落格
AJAX 無疑是主流的客戶端和伺服器端通訊的方式,AJAX 通訊方式當然有很多優點,但是缺點也一定程度上是由優點造成的,因為AJAX 通訊過程中,頁面不會全域性重新整理,這在傳輸的資料量比較小且網速比較好的時候,是沒有什麼問題的,但是當資料量比較大的時候,頁面就會長時間沒有任何反應,可能讓使用者誤以為請求失敗,所以在資料傳輸沒有完成的等待時間內,我們以一個進度條或者緩衝環給使用者以正在通訊的視覺化效果,這樣使用者體驗就會大大提升。
那麼怎麼實現呢?我們首先來看看 AJAX 的通訊原理。
一、 AJAX 通訊原理
W3C 一個工作草案規定了 Progress Event,定義了與客戶端和伺服器通訊有關的事件。這些事件最初只是針對 AJAX 操作,現在其他的 API 也開始借鑑。主要進度事件有六個:
- loadstart,當接收到伺服器相應的第一個位元組時觸發;
- progress,在接收資料期間不斷的觸發;
- error,當請求發生錯誤時觸發;
- abort,呼叫 abort 函式時觸發;
- load,接收資料完成時觸發;
- loadend,整個通訊過程完成後觸發。
這些事件各個瀏覽器的支援程度如何呢?我們可以看一幅圖:
目前,PC 瀏覽器只有 IE 不支援這些事件的所有實現,但是並不影響我們要使用的事件,Opera Mini 是針對手機的 Opera 瀏覽器,用的並不多。根據現在的支援程度,我們可以使用 Progress Events 實現一些應用,比如本文要實現的進度條。 本文要實現的“進度條”直接用到的事件是 `progress` 事件,各個瀏覽器都支援,是由 Mozilla 引入的革新。該事件觸發時,事件處理程式會接收一個事件物件 event,該事件物件包含四個我們要用到的屬性:
-
target,對應的 XHR 物件;
-
lengthComputable,表示進度資訊是否可用的布林值;
-
loaded,已經接收的位元組數;
-
total,響應資料的預期總位元組數,根據 Content-Length 響應頭部確定。
這樣我們通過監聽 progress 事件,檢視 position 的值與 total 的比值,就能確定接收資料的百分比,通過進度條顯示,即可完成預期效果。
二、 實現
注:
1、例子相容 IE 9+
2、使用了JQuery 和 Bootstrap 進度條
2.1 HTML 頁面
首先我們編輯 HTML 頁面,頁面中包含一個 bootstrap 進度條,同時包含一個按鈕,用以觸發請求資料,並同時修改進度條進度。HTML 頁面主要部分實現如下:
<div class="progress">
<div id="pros" class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
</div>
</div>
<button id="trigger_ajax" type="button" >請求資料</button>
控制進度條的已完成進度是 `id="pros"` 的 DIV 的 width 屬性,在進度條上顯示的進度文字,是 DIV 內含的文字 `text`,我們通過改變這兩個屬性,就可以實現進度的動態變化。
2.2 AJAX 請求
我們給按鈕繫結點選事件,用來請求伺服器端的資料:
var trigger = document.getElementById("trigger_ajax");
trigger.onclick = function(){
var xhr = new XMLHttpRequest();
xhr.onprogress = function(event){
if(event.lengthComputable){
var loaded = parseInt(event.loaded/event.total*100)+"%";
$('#pros').width(loaded);
$('#pros').text(loaded);
}
}
xhr.open("post", "for_test.php", true);
xhr.send(null);
}
注意,progress 事件要在 open 之前繫結,如果 event.lengthComputable
返回結果為 ture,那麼就根據伺服器的返回資料狀態改變進度條的狀態:
if(event.lengthComputable){
var loaded = parseInt(event.loaded/event.total*100)+"%";
$('#pros').width(loaded);
$('#pros').text(loaded);
}
2.3 伺服器端返回資料
最後我們要寫出伺服器端的程式碼,我使用的 PHP ,有一點需要注意,伺服器端的程式碼過程要“返回結果比較大,傳輸需要一段時間”,我們寫一個比較大的迴圈,組成一個非常長的字串,然後返回這個字串:
<?php
$results="";
for($i=1; $i<=900000; $i++){
$results.='"'.$i.'"';
}
$len = strlen($results);
header("Content-Length: $len");
echo $results;
?>
注意到 `header("Content-Length: $len");`,寫出 http 頭時候,附加 “Content-Length”,這樣 JS 端的 progress 事件的 event.lengthComputable 值才會為 `true`, event.total 才會在資料傳輸完畢之前取得值,否則 event.lengthComputable 值會返回 `false`, event.total 在資料完成之前值都是 `0`。
最後,我們執行頁面,可以看到:
三、 總結
我們可以把這個進度條應用在請求資料量比較大的情境中,在傳輸資料的過程中給使用者以直觀的視覺感知,這樣會提升使用者的體驗。或者應用在網路較差的情況下,請求時間可能會較長,當用戶觸發網路請求後,彈出一個包含進度條的彈出框,當請求完畢後,彈出框自動消失。
當然,表示進度,並不一定要使用條形,我們可以換成 環形等形狀,大致的原理都是一樣的,將後臺返回的進度動態改變前臺的緩衝進度。
當我們必須要在不支援 progress 事件的瀏覽器中實現類似功能時,我們可以利用所有瀏覽器都支援 AJAX 這個特性,請求開始和請求成功都有明確的時間點,我們退而求其次,不使用有刻度的進度條,而使用一個緩衝環,在請求完成之前,一直處於緩衝狀態。
這樣,至此為止,我們考慮了支援所有瀏覽器的 AJAX 請求進度顯示,和各個形狀的進度條。
OK,就寫到這裡吧!有什麼問題可以部落格下留言評論。
本文轉自 https://blog.csdn.net/qingyafan/article/details/49049061?spm=1001.2014.3001.5502,如有侵權,請聯絡刪除。