JavaScript 图像加载进度

问题描述 投票:0回答:7

JS有没有办法在图片加载时获取加载图片的进度? 我想使用HTML5新的Progress标签来显示加载图像的进度。

我希望有这样的东西:

var someImage = new Image()
someImage.onloadprogress = function(e) { progressBar.value = e.loaded / e.total };
someImage.src = "image.jpg";
javascript image html progress
7个回答
62
投票

这样,您就可以在 Image() 对象上添加 2 个新函数:

 Image.prototype.load = function(url){
        var thisImg = this;
        var xmlHTTP = new XMLHttpRequest();
        xmlHTTP.open('GET', url,true);
        xmlHTTP.responseType = 'arraybuffer';
        xmlHTTP.onload = function(e) {
            var blob = new Blob([this.response]);
            thisImg.src = window.URL.createObjectURL(blob);
        };
        xmlHTTP.onprogress = function(e) {
            thisImg.completedPercentage = parseInt((e.loaded / e.total) * 100);
        };
        xmlHTTP.onloadstart = function() {
            thisImg.completedPercentage = 0;
        };
        xmlHTTP.send();
    };

    Image.prototype.completedPercentage = 0;

在这里,您使用加载函数并将图像附加到 div 上。

var img = new Image();
img.load("url");
document.getElementById("myDiv").appendChild(img);

在加载状态期间,您可以使用

img.completedPercentage
检查进度百分比。


21
投票

为了增加改进,我修改了朱利安的答案(这又修改了塞巴斯蒂安的答案)。我已将逻辑移至函数中,而不是修改

Image
对象。该函数返回一个通过 URL 对象解析的
Promise
,只需将其作为
src
标签的
image
属性插入即可。

/**
 * Loads an image with progress callback.
 *
 * `onprogress` callback will be called by XMLHttpRequest's "onprogress"
 * event, and will receive the loading progress ratio as an whole number
 * (0 to 100). If progress ratio isn't computable, `onprogress` will be
 * called once, passing `-1` as progress value (this is useful to e.g. 
 * set progress bar animation to indeterminate).
 *
 * @param {string} imageUrl The image URL to load
 * @param {Function} onprogress
 * @return {Promise}
 */
function loadImage(imageUrl, onprogress) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    let notifiedNotComputable = false;

    xhr.open('GET', imageUrl, true);
    xhr.responseType = 'arraybuffer';

    xhr.onprogress = function(ev) {
      if (ev.lengthComputable) {
        onprogress(parseInt((ev.loaded / ev.total) * 100));
      } else {
        if (!notifiedNotComputable) {
          notifiedNotComputable = true;
          onprogress(-1);
        }
      }
    }

    xhr.onloadend = function() {
      if (!xhr.status.toString().match(/^2/)) {
        reject(xhr);
        
        return;
      }
      
      const options = {}
      const headers = xhr.getAllResponseHeaders();
      const m = headers.match(/^Content-Type\:\s*(.*?)$/mi);

      if (m && m[1]) {
        options.type = m[1];
      }

      resolve(window.URL.createObjectURL(
        new Blob([this.response], options)
      ));
    }

    xhr.send();
  });
}

/*****************
 * Example usage
 */

const imgContainer = document.getElementById('imgcont');
const progressBar = document.getElementById('progress');
const imageUrl = 'https://placekitten.com/g/2000/2000';

// "onprogress" callback.
function onProgressCallback(ratio) {
  if (ratio >= 0) {
    // We have progress ratio; update the bar.
    progressBar.value = ratio;
  } else {
    // Ratio not computable. Let's make this bar an indeterminate one.
    progressBar.removeAttribute('value');
  }
}

// Start image load.
loadImage(imageUrl, onProgressCallback)
  .then(imgSrc => {
    // Loading successfuly complete; set the image.
    imgContainer.src = imgSrc;
    
    // Hide progress bar.
    progressBar.style.display = 'none';
  })
  .catch(xhr => {
    // An error occured. We have the XHR object to see what happened.
  });
<progress id="progress" value="0" max="100" style="width: 100%;"></progress>

<img id="imgcont" />


19
投票

塞巴斯蒂安的回答非常好,是我见过的对这个问题最好的回答。然而,还有一些可能的改进。我使用他的代码修改如下:

Image.prototype.load = function( url, callback ) {
    var thisImg = this,
        xmlHTTP = new XMLHttpRequest();

    thisImg.completedPercentage = 0;

    xmlHTTP.open( 'GET', url , true );
    xmlHTTP.responseType = 'arraybuffer';

    xmlHTTP.onload = function( e ) {
        var h = xmlHTTP.getAllResponseHeaders(),
            m = h.match( /^Content-Type\:\s*(.*?)$/mi ),
            mimeType = m[ 1 ] || 'image/png';
            // Remove your progress bar or whatever here. Load is done.

        var blob = new Blob( [ this.response ], { type: mimeType } );
        thisImg.src = window.URL.createObjectURL( blob );
        if ( callback ) callback( this );
    };

    xmlHTTP.onprogress = function( e ) {
        if ( e.lengthComputable )
            thisImg.completedPercentage = parseInt( ( e.loaded / e.total ) * 100 );
        // Update your progress bar here. Make sure to check if the progress value
        // has changed to avoid spamming the DOM.
        // Something like: 
        // if ( prevValue != thisImage completedPercentage ) display_progress();
    };

    xmlHTTP.onloadstart = function() {
        // Display your progress bar here, starting at 0
        thisImg.completedPercentage = 0;
    };

    xmlHTTP.onloadend = function() {
        // You can also remove your progress bar here, if you like.
        thisImg.completedPercentage = 100;
    }

    xmlHTTP.send();
};

主要是添加了哑剧类型和一些小细节。按照塞巴斯蒂安的描述使用。效果很好。


5
投票

实际上,在最新的 chrome 中你可以使用它。

$progress = document.querySelector('#progress');

var url = 'https://placekitten.com/g/2000/2000';

var request = new XMLHttpRequest();
request.onprogress = onProgress;
request.onload = onComplete;
request.onerror = onError;

function onProgress(event) {
  if (!event.lengthComputable) {
    return;
  }
  var loaded = event.loaded;
  var total = event.total;
  var progress = (loaded / total).toFixed(2);

  $progress.textContent = 'Loading... ' + parseInt(progress * 100) + ' %';

  console.log(progress);
}

function onComplete(event) {
  var $img = document.createElement('img');
  $img.setAttribute('src', url);
  $progress.appendChild($img);
  console.log('complete', url);
}

function onError(event) {
  console.log('error');
}


$progress.addEventListener('click', function() {
  request.open('GET', url, true);
  request.overrideMimeType('text/plain; charset=x-user-defined');
  request.send(null);
});
<div id="progress">Click me to load</div>


1
投票

这里对 Julian Jensen 的代码进行了一个小更新,以便能够在加载图像后在 Canvas 中绘制图像:

xmlHTTP.onload = function( e ) {
        var h = xmlHTTP.getAllResponseHeaders(),
            m = h.match( /^Content-Type\:\s*(.*?)$/mi ),
            mimeType = m[ 1 ] || 'image/png';
            // Remove your progress bar or whatever here. Load is done.

        var blob = new Blob( [ this.response ], { type: mimeType } );
        thisImg.src = window.URL.createObjectURL( blob );

         thisImg.onload = function()
            {
                if ( callback ) callback( this );
            };
    };

1
投票

对于 xmlhttpreq v2 检查,请使用:

var xmlHTTP = new XMLHttpRequest();
if ('onprogress' in xmlHTTP) {
 // supported 
} else {
 // isn't supported
}

0
投票

如果你想处理加载的图像,那么你必须再添加一个函数,因为

thisImg.src = window.URL.createObjectURL(blob)

刚刚开始将图像作为线程处理。

你必须在加载原型的主体中添加一个新的函数,例如

  this.onload = function(e)
  {
    var canvas = document.createElement('canvas')

    canvas.width = this.width
    canvas.height = this.height

    canvas.getContext('2d').drawImage(this, 0, 0)
   }

这让我很头痛:)

© www.soinside.com 2019 - 2024. All rights reserved.