JavaScript 進(jìn)度事件

2023-03-20 15:47 更新

進(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、abortload等事件的后面。
  • 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í)候,因此有可能loaderror事件的監(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.lengthComputablefalseProgressEvent.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();


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)