Kiểm tra nếu một hình ảnh được tải (không có lỗi) với jQuery


224

Tôi đang sử dụng JavaScript với thư viện jQuery để thao tác hình thu nhỏ hình ảnh có trong danh sách không có thứ tự. Khi hình ảnh được tải, nó làm một việc, khi xảy ra lỗi, nó sẽ làm một việc khác. Tôi đang sử dụng jQuery load()error()các phương thức làm sự kiện. Sau những sự kiện này, tôi kiểm tra phần tử DOM hình ảnh cho .complete để đảm bảo hình ảnh chưa được tải trước khi jQuery có thể đăng ký các sự kiện.

Nó hoạt động chính xác trừ khi xảy ra lỗi trước khi jQuery có thể đăng ký các sự kiện. Giải pháp duy nhất tôi có thể nghĩ đến là sử dụng onerrorthuộc tính img để lưu trữ "cờ" ở đâu đó trên toàn cầu (hoặc trên nút tự nó) nói rằng nó không thành công để jQuery có thể kiểm tra "store / node" khi kiểm tra .complete.

Bất cứ ai có một giải pháp tốt hơn?

Chỉnh sửa: Các điểm chính được in đậm và thêm chi tiết bên dưới: Tôi đang kiểm tra xem một hình ảnh đã hoàn thành chưa (còn được tải) SAU Tôi thêm một sự kiện tải và lỗi trên hình ảnh. Bằng cách đó, nếu hình ảnh được tải trước khi các sự kiện được đăng ký, tôi vẫn sẽ biết. Nếu hình ảnh không được tải sau các sự kiện thì các sự kiện sẽ xử lý nó khi nó xảy ra. Vấn đề với điều này là, tôi có thể dễ dàng kiểm tra xem hình ảnh đã được tải chưa, nhưng tôi không thể biết liệu có xảy ra lỗi hay không.


Khi nào bạn đăng ký các sự kiện jQuery? Có thể một số mã sẽ giúp. :)
okw

Có rất nhiều mã, những gì tôi nói ở trên chỉ là một phiên bản rất đơn giản của những gì tôi đang làm. Tôi gọi các sự kiện sau khi DOM được tải, một phương thức được gọi để thêm các sự kiện vào hình thu nhỏ.
William

Câu trả lời:


250

Một tùy chọn khác là kích hoạt onloadvà / hoặc onerrorcác sự kiện bằng cách tạo một phần tử hình ảnh trong bộ nhớ và đặt srcthuộc tính của nó thành thuộc tính ban đầu srccủa ảnh gốc. Đây là một ví dụ về những gì tôi muốn nói:

$("<img/>")
    .on('load', function() { console.log("image loaded correctly"); })
    .on('error', function() { console.log("error loading image"); })
    .attr("src", $(originalImage).attr("src"))
;

Hi vọng điêu nay co ich!


27
Có vẻ như không hoạt động tốt như tôi hy vọng. Trong Google Chrome, dường như có vấn đề khi hình ảnh đã được lưu trong bộ nhớ cache. Nó không kích hoạt phương thức load (). :(
William

4
Ugg, bạn nói đúng. Chrome chắc chắn là trình duyệt khó chịu nhất để phát triển. Về mặt sáng sủa, tôi nghĩ rằng tôi có thể đã tìm thấy một công việc xung quanh: đặt nguồn hình ảnh thành "" rồi quay lại nguồn ban đầu. Tôi sẽ cập nhật câu trả lời của tôi.
Xavi

1
Bạn nên đặt .attrdòng sau sự .load.errordây chuyền. Nếu không, bạn có nguy cơ rằng hình ảnh có thể tải (hoặc gặp lỗi) trước khi các cuộc gọi lại được thêm vào và chúng sẽ không được gọi.
callum

19
@Xavi Chrome không phải là trình duyệt khó chịu nhất để phát triển, hãy thử phát triển cho Internet Explorer 7 trở xuống. Bên cạnh việc thêm tham số $ _GET vào tải hình ảnh, sẽ tải hình ảnh mới mọi lúc, như Gromix đề xuất.
SSH này vào

10
Các phương thức .load().error()gây nhầm lẫn và hiện không dùng nữa, sử dụng .on()và sử dụng loaderrornhư các sự kiện.
Firsh - LetsWP.io

235

Kiểm tra completenaturalWidthcác thuộc tính, theo thứ tự đó.

https://stereochro.me/ideas/detecting-broken-images-js

function IsImageOk(img) {
    // During the onload event, IE correctly identifies any images that
    // weren’t downloaded as not complete. Others should too. Gecko-based
    // browsers act like NS4 in that they report this incorrectly.
    if (!img.complete) {
        return false;
    }

    // However, they do have two very useful properties: naturalWidth and
    // naturalHeight. These give the true size of the image. If it failed
    // to load, either of these should be zero.
    if (img.naturalWidth === 0) {
        return false;
    }

    // No other way of checking: assume it’s ok.
    return true;
}

1
Thật thú vị, tôi đã xem bài đăng đó sớm hơn và tôi không nhận ra rằng họ đang làm! hoàn thành cho IE vì NaturalWidth không được xác định trong IE. Đi để kiểm tra nó bây giờ.
William

3
Rõ ràng, điều này chỉ hoạt động đáng tin cậy lần đầu tiên. Nếu sau đó bạn thay đổi src của hình ảnh, ít nhất safari mobile sẽ tiếp tục báo cáo giá trị đầu tiên cho cả NaturalWidth và hoàn tất.
giorgian

5
return img.complete && typeof img.naturalWidth! = 'không xác định' && img.naturalWidth! = 0;
Adrian Seeley

5
@vsync có thể bạn muốn sử dụng tính năng này dưới dạng kiểm tra một lần và nếu hình ảnh chưa được tải, hãy thiết lập trình xử lý sự kiện "tải". Không cần thiết phải đập CPU bằng cách chạy kiểm tra này nhiều lần.
Michael Martin-Smucker

2
Đối với những người tò mò, đây là khá chính xác những gì thư viện hình ảnh được tải liên kết dưới đây làm. Vì vậy, đối với việc sử dụng một lần, hãy sử dụng: github.com/desandro/imagesloaded/blob/master/
mẹo

57

Dựa trên hiểu biết của tôi về Đặc tả HTML của W3C cho imgphần tử , bạn sẽ có thể thực hiện việc này bằng cách sử dụng kết hợp các thuộc tính completenaturalHeight, như vậy:

function imgLoaded(imgElement) {
  return imgElement.complete && imgElement.naturalHeight !== 0;
}

Từ thông số kỹ thuật cho completethuộc tính:

Thuộc tính IDL hoàn thành phải trả về true nếu bất kỳ điều kiện nào sau đây là đúng:

  • Thuộc tính src bị bỏ qua.
  • Tác vụ cuối cùng được xếp hàng bởi nguồn tác vụ mạng sau khi tài nguyên đã được tìm nạp đã được xếp hàng.
  • Phần tử img hoàn toàn khả dụng.
  • Phần tử img bị hỏng.

Nếu không, thuộc tính phải trả về false.

Vì vậy, về cơ bản, completetrả về true nếu hình ảnh đã tải xong hoặc không tải được. Vì chúng tôi chỉ muốn trường hợp hình ảnh được tải thành công, chúng tôi cũng cần kiểm tra nauturalHeightthuộc tính:

Các thuộc tính IDL naturalWidthnaturalHeightphải trả về chiều rộng và chiều cao nội tại của hình ảnh, bằng pixel pixel, nếu hình ảnh có sẵn, hoặc khác 0.

availableđược định nghĩa như vậy:

Một img luôn ở một trong các trạng thái sau:

  • Không khả dụng - Tác nhân người dùng chưa thu được bất kỳ dữ liệu hình ảnh nào.
  • Có sẵn một phần - Tác nhân người dùng đã thu được một số dữ liệu hình ảnh.
  • Hoàn toàn khả dụng - Tác nhân người dùng đã thu được tất cả dữ liệu hình ảnh và ít nhất là kích thước hình ảnh có sẵn.
  • Bị hỏng - Tác nhân người dùng đã thu được tất cả dữ liệu hình ảnh có thể, nhưng thậm chí không thể giải mã hình ảnh đủ để có được kích thước hình ảnh (ví dụ: hình ảnh bị hỏng hoặc định dạng không được hỗ trợ hoặc không thể lấy được dữ liệu) .

Khi một phần tử img ở trạng thái khả dụng một phần hoặc ở trạng thái hoàn toàn khả dụng, nó được cho là có sẵn.

Vì vậy, nếu hình ảnh bị "hỏng" (không tải được), thì nó sẽ ở trạng thái bị hỏng, không phải là trạng thái khả dụng, do đó naturalHeightsẽ là 0.

Do đó, kiểm tra imgElement.complete && imgElement.naturalHeight !== 0sẽ cho chúng tôi biết hình ảnh đã được tải thành công hay chưa.

Bạn có thể đọc thêm về điều này trong Đặc tả HTML của W3C cho imgphần tử hoặc trên MDN .


1
Không hoạt động là hình ảnh được tải với kiểu "nội dung: url"
deathangel908

1
Điều này dường như không hoạt động trong Firefox với hình ảnh SVG khi trình duyệt báo cáo chiều cao / chiều rộng tự nhiên là 0. Lỗi có liên quan: bugzilla.mozilla.org/show_orms.cgi?id=1328124
leeb

20

Tôi đã thử nhiều cách khác nhau và cách này là cách duy nhất làm việc cho tôi

//check all images on the page
$('img').each(function(){
    var img = new Image();
    img.onload = function() {
        console.log($(this).attr('src') + ' - done!');
    }
    img.src = $(this).attr('src');
});

Bạn cũng có thể thêm chức năng gọi lại được kích hoạt sau khi tất cả các hình ảnh được tải trong DOM và sẵn sàng. Điều này áp dụng cho hình ảnh được thêm động. http://jsfiddle.net/kalmarsh80/nrAPk/


liên kết jsfiddle bị hỏng
Alex Karshin

1
Tôi đã kiểm tra các lần đọc thú vị ở trên và chúng thất bại giữa các bài kiểm tra được lưu trữ / không lưu trữ trên một số trình duyệt phổ biến. Câu trả lời này tương tự câu trả lời khác nhưng là câu tôi đã triển khai và thử nghiệm ngay bây giờ, tôi có thể xác nhận nó hoạt động trên: EdgeWin10, IE11Win8.1, Win7IE10, Win7IE9, iOS 10.2 Chrome, iOS 10.2 Safari, mac os 10.12 Chrome, mac os 10.12 Safari, mac os 10.12 Firefox, Google Pixel 7.1, Samsung S5 Android 4.4. Đừng quên sử dụng addEventListener / removeEventListener: D
danjah 9/12/2016

13

Sử dụng imagesLoadedthư viện javascript .

Có thể sử dụng với Javascript đơn giản và như một plugin jQuery.

Đặc trưng:

Tài nguyên


Điều này làm việc hoàn hảo cho tôi. function checkImages (imss) {$ (imss) .each (function () {$ (imss) .imagesLoaded () .proTHER (function (dụ, image) {if (image.isLoaded == false) {console.log (image .img.src + 'không thể tìm thấy.'); image.img.src = "/temsheet/img/no-image.jpg";}});}); }
Rooster242

1
nó dường như có TẤN các vấn đề mở mà các lỗi lớn và nhà phát triển dường như không bắt kịp với chúng. như bây giờ, điều này là hoàn toàn không thể sử dụng trong môi trường sản xuất.
vsync

3
@vsync Bạn đã đọc một số vấn đề mở chưa? Anh ta trả lời gần như tất cả trong số họ, và hầu hết là những trường hợp cạnh không thể giải quyết được mà ít người khác gặp phải. Tôi chưa bao giờ gặp vấn đề với nó trong sản xuất.
Josh Harrison

1
vâng, tôi tự sử dụng và đôi khi nó không hoạt động, vì vậy tôi sử dụng setTimeout để bao gồm các trường hợp không thành công
vsync

Có nhiều lý do TẠI SAO một người muốn sử dụng plugin hình ảnh được tải: thuộc completetính dường như không được hỗ trợ rõ ràng: không thể tìm thấy một nguồn thông tin đáng tin cậy về hỗ trợ trình duyệt. completethuộc tính dường như cũng không có thông số kỹ thuật rõ ràng: thông số HTML5 là người duy nhất đề cập đến nó và nó vẫn ở phiên bản nháp tại thời điểm viết. Nếu bạn sử dụng naturalWidthnaturalHeightchỉ có hỗ trợ IE9 +, vì vậy nếu bạn sử dụng nó để tìm hiểu xem hình ảnh đã được tải chưa, bạn cần một số mẹo "thông minh" để làm cho nó hoạt động trên các trình duyệt cũ và bạn phải kiểm tra hành vi của trình duyệt chéo có phù hợp không
Adrien Trở thành

8

Truy xuất thông tin từ các thành phần hình ảnh trên trang
Kiểm tra hoạt động trên Chrome và Firefox
Làm việc jsFiddle (mở bảng điều khiển của bạn để xem kết quả)

$('img').each(function(){ // selecting all image element on the page

    var img = new Image($(this)); // creating image element

    img.onload = function() { // trigger if the image was loaded
        console.log($(this).attr('src') + ' - done!');
    }

    img.onerror = function() { // trigger if the image wasn't loaded
        console.log($(this).attr('src') + ' - error!');
    }

    img.onAbort = function() { // trigger if the image load was abort
        console.log($(this).attr('src') + ' - abort!');
    }

    img.src = $(this).attr('src'); // pass src to image object

    // log image attributes
    console.log(img.src);
    console.log(img.width);
    console.log(img.height);
    console.log(img.complete);

});

Lưu ý: Tôi đã sử dụng jQuery , tôi nghĩ rằng điều này có thể đạt được trên javascript đầy đủ

Tôi tìm thấy thông tin tốt ở đây OpenClassRoom -> đây là một diễn đàn của Pháp


3

Trình phát hiện mạng thời gian thực - kiểm tra trạng thái mạng mà không làm mới trang: (nó không phải là jquery, nhưng đã được kiểm tra và hoạt động 100%: (được thử nghiệm trên Firefox v25.0))

Mã số:

<script>
 function ImgLoad(myobj){
   var randomNum = Math.round(Math.random() * 10000);
   var oImg=new Image;
   oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
   oImg.onload=function(){alert('Image succesfully loaded!')}
   oImg.onerror=function(){alert('No network connection or image is not available.')}
}
window.onload=ImgLoad();
</script>

<button id="reloadbtn" onclick="ImgLoad();">Again!</button>

nếu mất kết nối, chỉ cần nhấn nút Again.

Cập nhật 1: Tự động phát hiện mà không cần làm mới trang:

<script>
     function ImgLoad(myobj){
       var randomNum = Math.round(Math.random() * 10000);
       var oImg=new Image;
       oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
       oImg.onload=function(){networkstatus_div.innerHTML="";}
       oImg.onerror=function(){networkstatus_div.innerHTML="Service is not available. Please check your Internet connection!";}
}

networkchecker = window.setInterval(function(){window.onload=ImgLoad()},1000);
</script>

<div id="networkstatus_div"></div>

100%! Điều gì xảy ra nếu liên kết hình ảnh của bạn bị chặn bởi proxy / tường lửa hoặc máy chủ hình ảnh không phản hồi? Bạn vẫn có mạng hoạt động :)
Sen Jacob

Điều này sẽ tải mọi hình ảnh một lần nữa từ máy chủ, phá vỡ bộ đệm (cố ý). Vì vậy, chỉ để kiểm tra, bạn (ít nhất) nhân đôi băng thông cho tất cả các hình ảnh của bạn. Bên cạnh đó, nó chỉ kiểm tra nếu hình ảnh tồn tại trên máy chủ, chứ không phải liệu nó có được tải ở một nơi cụ thể không. Cũng không có cách nào để biết khi nào mỗi hình ảnh được tải.
Marius Balčytis

3

Sau khi đọc các giải pháp thú vị trên trang này, tôi đã tạo ra một giải pháp dễ sử dụng chịu ảnh hưởng rất lớn từ bài đăng của SLaks và Noyo dường như đang hoạt động trên các phiên bản gần đây (như viết) của Chrome, IE, Firefox, Safari và Opera (tất cả trên Windows). Ngoài ra, nó hoạt động trên trình giả lập iPhone / iPad mà tôi đã sử dụng.

Một điểm khác biệt chính giữa giải pháp này và bài đăng của SLaks và Noyo là giải pháp này chủ yếu kiểm tra các thuộc tính tự nhiên và độ sáng tự nhiên. Tôi đã thấy rằng trong các phiên bản trình duyệt hiện tại, hai thuộc tính đó dường như cung cấp kết quả nhất quán và hữu ích nhất.

Mã này trả về ĐÚNG khi một hình ảnh đã được tải đầy đủ VÀ thành công. Nó trả về SAI khi một hình ảnh chưa được tải đầy đủ HOẶC không tải được.

Một điều bạn sẽ cần lưu ý là chức năng này cũng sẽ trả về SAI nếu hình ảnh là hình ảnh pixel 0x0. Nhưng những hình ảnh đó khá hiếm và tôi không thể nghĩ ra một trường hợp rất hữu ích khi bạn muốn kiểm tra xem hình ảnh pixel 0x0 đã được tải chưa :)

Trước tiên, chúng tôi đính kèm một chức năng mới gọi là "isLoaded" vào nguyên mẫu HTMLImageEuity, để chức năng này có thể được sử dụng trên bất kỳ thành phần hình ảnh nào.

HTMLImageElement.prototype.isLoaded = function() {

    // See if "naturalWidth" and "naturalHeight" properties are available.
    if (typeof this.naturalWidth == 'number' && typeof this.naturalHeight == 'number')
        return !(this.naturalWidth == 0 && this.naturalHeight == 0);

    // See if "complete" property is available.
    else if (typeof this.complete == 'boolean')
        return this.complete;

    // Fallback behavior: return TRUE.
    else
        return true;

};

Sau đó, bất cứ khi nào chúng tôi cần kiểm tra trạng thái tải của hình ảnh, chúng tôi chỉ cần gọi chức năng "isLoaded".

if (someImgElement.isLoaded()) {
    // YAY! The image loaded
}
else {
    // Image has not loaded yet
}

Nhận xét của mỗi giorgian trên bài đăng của SLaks và Noyo, giải pháp này có lẽ chỉ có thể được sử dụng dưới dạng kiểm tra một lần trên Safari Mobile nếu bạn có kế hoạch thay đổi thuộc tính SRC. Nhưng bạn có thể giải quyết vấn đề đó bằng cách tạo một thành phần hình ảnh với thuộc tính SRC mới thay vì thay đổi thuộc tính SRC trên thành phần hình ảnh hiện có.


2

Đây là cách tôi làm cho nó hoạt động trên trình duyệt chéo bằng cách sử dụng kết hợp các phương pháp ở trên (tôi cũng cần phải chèn hình ảnh động vào dom):

$('#domTarget').html('<img src="" />');

var url = '/some/image/path.png';

$('#domTarget img').load(function(){}).attr('src', url).error(function() {
    if ( isIE ) {
       var thisImg = this;
       setTimeout(function() {
          if ( ! thisImg.complete ) {
             $(thisImg).attr('src', '/web/css/img/picture-broken-url.png');
          }
       },250);
    } else {
       $(this).attr('src', '/web/css/img/picture-broken-url.png');
    }
});

Lưu ý: Bạn sẽ cần cung cấp trạng thái boolean hợp lệ cho biến isIE.


2
var isImgLoaded = function(imgSelector){
  return $(imgSelector).prop("complete") && $(imgSelector).prop("naturalWidth") !== 0;
}

// Hoặc là một Plugin

    $.fn.extend({
      isLoaded: function(){
        return this.prop("complete") && this.prop("naturalWidth") !== 0;
      }
    })

// $(".myImage").isLoaded() 

1

Theo tôi hiểu thuộc tính .complete là không chuẩn. Nó có thể không phổ biến ... Tôi nhận thấy nó dường như hoạt động khác trong IE câu IE. Tôi đang tải một số hình ảnh trong javascript sau đó kiểm tra nếu hoàn thành. Trong Firefox, điều này dường như hoạt động rất tốt. Trong IE, không phải vì hình ảnh dường như đang tải trên một luồng khác. Nó chỉ hoạt động nếu tôi đặt độ trễ giữa nhiệm vụ của mình cho image.src và khi tôi kiểm tra thuộc tính image.complete.

Sử dụng image.onload và image.onerror cũng không hoạt động với tôi, bởi vì tôi cần truyền một tham số để biết tôi đang nói về hình ảnh nào khi hàm được gọi. Bất kỳ cách nào để làm điều đó dường như thất bại bởi vì nó thực sự dường như vượt qua cùng một chức năng, không phải các trường hợp khác nhau của cùng một chức năng. Vì vậy, giá trị tôi truyền vào nó để xác định hình ảnh luôn luôn là giá trị cuối cùng trong vòng lặp. Tôi không thể nghĩ ra bất kỳ cách nào xung quanh vấn đề này.

Trên Safari và Chrome, tôi đang thấy image.complete đúng và NaturalWidth được đặt ngay cả khi bảng điều khiển lỗi hiển thị 404 cho hình ảnh đó ... và tôi cố tình xóa hình ảnh đó để kiểm tra điều này. Nhưng những điều trên hoạt động tốt cho Firefox và IE.


Hmm, thật thú vị. Có phiền khi đăng một ví dụ mã để tôi muốn thử một vài thứ không?
Xavi

1

Đoạn mã này đã giúp tôi khắc phục các sự cố bộ nhớ đệm của trình duyệt:

$("#my_image").on('load', function() {

    console.log("image loaded correctly"); 
}).each(function() {

     if($(this).prop('complete')) $(this).load();
});

Khi bộ đệm của trình duyệt bị tắt, chỉ có mã này không hoạt động:

$("#my_image").on('load', function() {
     console.log("image loaded correctly"); 
})

để làm cho nó hoạt động, bạn phải thêm:

.each(function() {
     if($(this).prop('complete')) $(this).load();
});

0

Sử dụng JavaScriptmã này bạn có thể kiểm tra hình ảnh đã được tải thành công hay chưa.

document.onready = function(e) {
        var imageobj = new Image();
        imageobj.src = document.getElementById('img-id').src;
        if(!imageobj.complete){ 
            alert(imageobj.src+"  -  Not Found");
        }
}

Hãy thử nó


0

Tôi đã có rất nhiều vấn đề với việc tải hoàn toàn một hình ảnh và EventListener.

Bất cứ điều gì tôi đã cố gắng, kết quả là không đáng tin cậy.

Nhưng sau đó tôi đã tìm ra giải pháp. Về mặt kỹ thuật nó không phải là một cái đẹp, nhưng bây giờ tôi không bao giờ tải hình ảnh thất bại.

Tôi đã làm gì:

                    document.getElementById(currentImgID).addEventListener("load", loadListener1);
                    document.getElementById(currentImgID).addEventListener("load", loadListener2);

                function loadListener1()
                    {
                    // Load again
                    }

                function loadListener2()
                {
                    var btn = document.getElementById("addForm_WithImage"); btn.disabled = false;
                    alert("Image loaded");
                }

Thay vì tải hình ảnh một lần, tôi chỉ tải nó lần thứ hai trực tiếp sau lần đầu tiên và cả hai đều chạy qua máng sự kiện.

Tất cả những cơn đau đầu của tôi đã biến mất!


Nhân tiện: Các bạn từ stackoverflow đã giúp tôi hơn gấp trăm lần. Đối với điều này rất lớn Cảm ơn bạn!


0

Cái này hoạt động tốt với tôi :)

$('.progress-image').each(function(){
    var img = new Image();
    img.onload = function() {
        let imgSrc = $(this).attr('src');
        $('.progress-image').each(function(){
            if($(this).attr('src') == imgSrc){
                console.log($(this).parent().closest('.real-pack').parent().find('.shimmer').fadeOut())
            }
        })
    }
    img.src = $(this).attr('src');
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.