图片的 JavaScript 加载进度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14218607/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript loading progress of an image
提问by Light
Is there a way in JS to get the progress of a loading image while the image is being loaded? I want to use the new Progress tag of HTML5 to show the progress of loading images.
JS中有没有办法在加载图像时获取加载图像的进度?我想使用 HTML5 的新 Progress 标签来显示加载图像的进度。
I wish there was something like:
我希望有类似的东西:
var someImage = new Image()
someImage.onloadprogress = function(e) { progressBar.value = e.loaded / e.total };
someImage.src = "image.jpg";
回答by Sebastián Espinosa
With this, you add 2 new functions on the Image() object:
有了这个,您在 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;
And here you use the load function and append the image on a div.
在这里,您使用加载函数并将图像附加到 div 上。
var img = new Image();
img.load("url");
document.getElementById("myDiv").appendChild(img);
During the loading state you can check the progress percentage using img.completedPercentage.
在加载状态期间,您可以使用 来检查进度百分比img.completedPercentage。
回答by Julian Jensen
Sebastian's answer is excellent, the best I've seen to this question. There are, however, a few possible improvements. I use his code modified like this:
塞巴斯蒂安的回答非常好,是我对这个问题见过的最好的回答。但是,有一些可能的改进。我使用他的代码修改如下:
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();
};
Mainly I added a mime-type and some minor details. Use as Sebastian describes. Works well.
主要是我添加了一个哑剧类型和一些小细节。按照塞巴斯蒂安的描述使用。效果很好。
回答by Parziphal
Just to add to the improvements, I've modified Julian's answer (which in turn modified Sebastian's). I've moved the logic to a function instead of modifying the Imageobject. This function returns a Promisethat resolves with the URL object, which only needs to be inserted as the srcattribute of an imagetag.
只是为了增加改进,我修改了朱利安的答案(反过来修改了塞巴斯蒂安的)。我已将逻辑移至函数而不是修改Image对象。该函数返回一个Promise用URL对象解析的a ,只需要作为标签的src属性插入即可image。
/**
* Loads an image with progress callback.
*
* The `onprogress` callback will be called by XMLHttpRequest's onprogress
* event, and will receive the loading progress ratio as an whole number.
* However, if it's not possible to compute the progress ratio, `onprogress`
* will be called only once passing -1 as progress value. This is useful to,
* for example, change the progress animation to an undefined animation.
*
* @param {string} imageUrl The image to load
* @param {Function} onprogress
* @return {Promise}
*/
function loadImage(imageUrl, onprogress) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
var 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);
} else {
if (!notifiedNotComputable) {
onprogress(100);
}
var options = {}
var headers = xhr.getAllResponseHeaders();
var m = headers.match(/^Content-Type\:\s*(.*?)$/mi);
if (m && m[1]) {
options.type = m[1];
}
var blob = new Blob([this.response], options);
resolve(window.URL.createObjectURL(blob));
}
}
xhr.send();
});
}
/*****************
* Example usage
*/
var imgContainer = document.getElementById('imgcont');
var progressBar = document.getElementById('progress');
var imageUrl = 'https://placekitten.com/g/2000/2000';
loadImage(imageUrl, (ratio) => {
if (ratio == -1) {
// Ratio not computable. Let's make this bar an undefined one.
// Remember that since ratio isn't computable, calling this function
// makes no further sense, so it won't be called again.
progressBar.removeAttribute('value');
} else {
// We have progress ratio; update the bar.
progressBar.value = ratio;
}
})
.then(imgSrc => {
// Loading successfuly complete; set the image and probably do other stuff.
imgContainer.src = imgSrc;
}, 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" />
回答by Chris Panayotoff
Actually, in latest chrome you can use it.
实际上,在最新的 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>
回答by kamel B
Here is a small update of the code of Julian Jensen in order to be able to draw the image in a Canvas after it is loaded :
这是 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 );
};
};
回答by Pavel Zheliba
for xmlhttpreq v2 check, use:
对于 xmlhttpreq v2 检查,请使用:
var xmlHTTP = new XMLHttpRequest();
if ('onprogress' in xmlHTTP) {
// supported
} else {
// isn't supported
}
回答by Hollay-Horváth Zsombor
If you want to process your loaded image, than you have to add one more function, because
如果要处理加载的图像,则必须再添加一项功能,因为
thisImg.src = window.URL.createObjectURL(blob)
just starts to process the image as a thread.
刚刚开始将图像作为线程处理。
You have to add a new a function to the body of load prototype, like
您必须在加载原型的主体中添加一个新的函数,例如
this.onload = function(e)
{
var canvas = document.createElement('canvas')
canvas.width = this.width
canvas.height = this.height
canvas.getContext('2d').drawImage(this, 0, 0)
}
This make me headache to realize :)
这让我头疼地意识到:)

