JavaScript 進度事件

2023-03-20 15:47 更新

進度事件的種類

進度事件用來描述資源加載的進度,主要由 AJAX 請求、<img>、<audio>、<video><style>、<link>等外部資源的加載觸發(fā),繼承了ProgressEvent接口。它主要包含以下幾種事件。

  • abort:外部資源中止加載時(比如用戶取消)觸發(fā)。如果發(fā)生錯誤導致中止,不會觸發(fā)該事件。
  • error:由于錯誤導致外部資源無法加載時觸發(fā)。
  • load:外部資源加載成功時觸發(fā)。
  • loadstart:外部資源開始加載時觸發(fā)。
  • loadend:外部資源停止加載時觸發(fā),發(fā)生順序排在errorabort、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。如果加載失敗,就把圖片元素的樣式設置為不顯示。

有時候,圖片加載會在腳本運行之前就完成,尤其是當腳本放置在網頁底部的時候,因此有可能loaderror事件的監(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.lengthComputablefalse,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();


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號