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