進度事件的種類
進度事件用來描述資源加載的進度,主要由 AJAX 請求、<img>
、<audio>
、<video>
、<style>
、<link>
等外部資源的加載觸發(fā),繼承了ProgressEvent
接口。它主要包含以下幾種事件。
abort
:外部資源中止加載時(比如用戶取消)觸發(fā)。如果發(fā)生錯誤導致中止,不會觸發(fā)該事件。error
:由于錯誤導致外部資源無法加載時觸發(fā)。load
:外部資源加載成功時觸發(fā)。loadstart
:外部資源開始加載時觸發(fā)。loadend
:外部資源停止加載時觸發(fā),發(fā)生順序排在error
、abort
、load
等事件的后面。progress
:外部資源加載過程中不斷觸發(fā)。timeout
:加載超時時觸發(fā)。
注意,除了資源下載,文件上傳也存在這些事件。
下面是一個例子。
image.addEventListener('load', function (event) {
image.classList.add('finished');
});
image.addEventListener('error', function (event) {
image.style.display = 'none';
});
上面代碼在圖片元素加載完成后,為圖片元素添加一個finished
的 Class。如果加載失敗,就把圖片元素的樣式設置為不顯示。
有時候,圖片加載會在腳本運行之前就完成,尤其是當腳本放置在網頁底部的時候,因此有可能load
和error
事件的監(jiān)聽函數(shù)根本不會執(zhí)行。所以,比較可靠的方式,是用complete
屬性先判斷一下是否加載完成。
function loaded() {
// ...
}
if (image.complete) {
loaded();
} else {
image.addEventListener('load', loaded);
}
由于 DOM 的元素節(jié)點沒有提供是否加載錯誤的屬性,所以error
事件的監(jiān)聽函數(shù)最好放在<img>
元素的 HTML 代碼中,這樣才能保證發(fā)生加載錯誤時百分之百會執(zhí)行。
<img src="/wrong/url" onerror="this.style.display='none';" />
loadend
事件的監(jiān)聽函數(shù),可以用來取代abort
事件、load
事件、error
事件的監(jiān)聽函數(shù),因為它總是在這些事件之后發(fā)生。
req.addEventListener('loadend', loadEnd, false);
function loadEnd(e) {
console.log('傳輸結束,成功失敗未知');
}
loadend
事件本身不提供關于進度結束的原因,但可以用它來做所有加載結束場景都需要做的一些操作。
另外,error
事件有一個特殊的性質,就是不會冒泡。所以,子元素的error
事件,不會觸發(fā)父元素的error
事件監(jiān)聽函數(shù)。
ProgressEvent 接口
ProgressEvent
接口主要用來描述外部資源加載的進度,比如 AJAX 加載、<img>
、<video>
、<style>
、<link>
等外部資源加載。進度相關的事件都繼承了這個接口。
瀏覽器原生提供了ProgressEvent()
構造函數(shù),用來生成事件實例。
new ProgressEvent(type, options)
ProgressEvent()
構造函數(shù)接受兩個參數(shù)。第一個參數(shù)是字符串,表示事件的類型,這個參數(shù)是必須的。第二個參數(shù)是一個配置對象,表示事件的屬性,該參數(shù)可選。配置對象除了可以使用Event
接口的配置屬性,還可以使用下面的屬性,所有這些屬性都是可選的。
lengthComputable
:布爾值,表示加載的總量是否可以計算,默認是false
。loaded
:整數(shù),表示已經加載的量,默認是0
。total
:整數(shù),表示需要加載的總量,默認是0
。
ProgressEvent
具有對應的實例屬性。
ProgressEvent.lengthComputable
ProgressEvent.loaded
ProgressEvent.total
如果ProgressEvent.lengthComputable
為false
,ProgressEvent.total
實際上是沒有意義的。
下面是一個例子。
var p = new ProgressEvent('load', {
lengthComputable: true,
loaded: 30,
total: 100,
});
document.body.addEventListener('load', function (e) {
console.log('已經加載:' + (e.loaded / e.total) * 100 + '%');
});
document.body.dispatchEvent(p);
// 已經加載:30%
上面代碼先構造一個load
事件,拋出后被監(jiān)聽函數(shù)捕捉到。
下面是一個實際的例子。
var xhr = new XMLHttpRequest();
xhr.addEventListener('progress', updateProgress, false);
xhr.addEventListener('load', transferComplete, false);
xhr.addEventListener('error', transferFailed, false);
xhr.addEventListener('abort', transferCanceled, false);
xhr.open();
function updateProgress(e) {
if (e.lengthComputable) {
var percentComplete = e.loaded / e.total;
} else {
console.log('不能計算進度');
}
}
function transferComplete(e) {
console.log('傳輸結束');
}
function transferFailed(evt) {
console.log('傳輸過程中發(fā)生錯誤');
}
function transferCanceled(evt) {
console.log('用戶取消了傳輸');
}
上面是下載過程的進度事件,還存在上傳過程的進度事件。這時所有監(jiān)聽函數(shù)都要放在XMLHttpRequest.upload
對象上面。
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', updateProgress, false);
xhr.upload.addEventListener('load', transferComplete, false);
xhr.upload.addEventListener('error', transferFailed, false);
xhr.upload.addEventListener('abort', transferCanceled, false);
xhr.open();
更多建議: