jQuery / JavaScript untuk mengganti gambar yang rusak


547

Saya memiliki halaman web yang mencakup banyak gambar. Terkadang gambar tidak tersedia, jadi gambar yang rusak ditampilkan di browser klien.

Bagaimana cara menggunakan jQuery untuk mendapatkan set gambar, memfilternya ke gambar yang rusak kemudian mengganti src?


--Saya pikir akan lebih mudah untuk melakukan ini dengan jQuery, tetapi ternyata jauh lebih mudah untuk hanya menggunakan solusi JavaScript murni, yaitu, yang disediakan oleh Prestaul.

Jawaban:


760

Tangani onErroracara untuk gambar untuk menetapkan kembali sumbernya menggunakan JavaScript:

function imgError(image) {
    image.onerror = "";
    image.src = "/images/noimage.gif";
    return true;
}
<img src="image.png" onerror="imgError(this);"/>

Atau tanpa fungsi JavaScript:

<img src="image.png" onError="this.onerror=null;this.src='/images/noimage.gif';" />

Tabel kompatibilitas berikut mencantumkan browser yang mendukung fasilitas kesalahan:

http://www.quirksmode.org/dom/events/error.html


132
Anda mungkin ingin menghapus teror sebelum mengatur src. Kalau tidak, jika noimage.gif juga hilang, Anda mungkin berakhir dengan "stack overflow".
pcorcoran

45
Saya pikir & berharap kami bergerak menjauh dari inline atribut untuk acara javascript ...
redsquare

24
redsquare ... mereka sangat bisa dimengerti ketika Anda bijaksana untuk mengendalikan mereka dan bahkan dapat berguna ketika Anda ingin markup Anda mencerminkan apa yang sebenarnya akan terjadi.
Nicole

2
Poin bagus NickC, tentang markup yang menunjukkan apa yang terjadi, saya hanya merasa ngeri ketika saya melihatnya: P
SSH

38
@redsquare, saya sepenuhnya setuju, tapi ini kasus unik. Inline adalah satu-satunya tempat di mana Anda dapat melampirkan pendengar dengan pasti bahwa acara tidak akan memicu sebelum pendengar Anda dilampirkan. Jika Anda melakukannya di akhir dokumen atau menunggu DOM dimuat, Anda mungkin kehilangan acara kesalahan pada beberapa gambar. Tidak ada gunanya Anda melampirkan penangan kesalahan setelah acara telah dipecat.
Prestaul

201

Saya menggunakan errorhandler bawaan:

$("img").error(function () {
    $(this).unbind("error").attr("src", "broken.gif");
});

Edit: The error()Metode ini usang dalam jquery 1,8 dan lebih tinggi. Sebagai gantinya, Anda sebaiknya menggunakan .on("error"):

$("img").on("error", function () {
    $(this).attr("src", "broken.gif");
});

112
Jika Anda menggunakan teknik ini, Anda dapat menggunakan metode "satu" untuk menghindari keharusan melepaskan ikatan acara: $ ('img'). One ('error', function () {this.src = 'broken.gif';}) ;
Prestaul

7
+1 Tetapi apakah Anda harus melepaskan ikatannya? Ini berfungsi dengan baik pada gambar dinamis (mis. Gambar yang dapat berubah saat digerakkan) jika Anda tidak melepaskannya.
Aximili

15
Saya pikir jika Anda tidak melepaskan ikatannya, dan referensi src broken.gif pernah gagal dimuat karena alasan apa pun, maka hal-hal buruk dapat terjadi di browser.
travis

4
@ Travis, pada titik apa Anda akan menelepon? Apakah ada cara untuk menggunakan metode ini dan memastikan bahwa pawang Anda dilampirkan SEBELUM acara kesalahan menyala?
Prestaul

5
Berikut ini adalah contoh kasus di mana kesalahan terjadi sebelum event handler dilampirkan: jsfiddle.net/zmpGz/1 Saya benar-benar ingin tahu apakah ada cara gagal-aman untuk memasang handler ini ...
Prestaul

120

Jika seseorang seperti saya, cobalah untuk melampirkan erroracara tersebut ke HTML dinamisimg tag , saya ingin menunjukkan bahwa:

Rupanya imgacara kesalahan tidak menggelembung di sebagian besar browser, bertentangan dengan standar apa dikatakan .

Jadi, sesuatu seperti yang berikut ini tidak akan berfungsi :

$(document).on('error', 'img', function () { ... })

Semoga ini bisa membantu orang lain. Saya berharap saya telah melihat ini di sini di utas ini. Tapi saya tidak melakukannya. Jadi, saya menambahkannya


tidak bekerja Saya memuat gambar mati secara dinamis dan menambahkannya ke dom, dan tidak ada acara 'kesalahan' dipecat.
vsync

59

Berikut ini adalah solusi mandiri:

$(window).load(function() {
  $('img').each(function() {
    if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
      // image was broken, replace with your new image
      this.src = 'http://www.tranism.com/weblog/images/broken_ipod.gif';
    }
  });
});

5
Hampir benar ... gambar yang benar di IE masih akan kembali (typeof (this.naturalWidth) == "undefined") == true; - Saya mengubah pernyataan if ke (! This.complete || (! $. Browser.msie && (ketik this.naturalWidth == "undefined" || this.naturalWidth == 0)))
Sugendran

3
aturan ini karena dapat mendeteksi gambar yang rusak setelah memuat halaman. aku butuh ini.
northamerican

@Sugendran $.browsertelah ditinggalkan dan dihapus sekarang, gunakan deteksi fitur (semakin rumit dalam kasus ini).
lee penkman

3
Standalone tetapi membutuhkan jQuery?
Charlie

Ini berfungsi dengan baik, tetapi ketika src dari gambar kembali 204 No Contentitu akan menjadi gambar yang rusak.
Carson Reinke

35

Saya percaya ini yang Anda cari: jQuery.Preload

Berikut ini contoh kode dari demo, Anda menentukan pemuatan dan tidak menemukan gambar dan Anda siap:

$('#images img').preload({
    placeholder:'placeholder.jpg',
    notFound:'notfound.jpg'
});

1
jQuery.Preload adalah sebuah plugin yang diperlukan untuk menggunakan kode contoh.
Dan Lord

17
Ya ... ini terkait dengan jawaban di baris pertama.
Nick Craver

Terima kasih, Nick, ini tampaknya menjadi solusi yang bagus untuk masalah Firefox yang berumur 8+ tahun tidak menunjukkan penggantian gambar untuk gambar yang rusak. Plus Anda dapat memberi merek hal kecil ... terima kasih lagi.
klewis


19

Sementara OP sedang mencari untuk mengganti SRC, saya yakin banyak orang yang memukul pertanyaan ini mungkin hanya ingin menyembunyikan gambar yang rusak, dalam hal ini solusi sederhana ini bekerja sangat baik untuk saya.

Menggunakan JavaScript Inline:

<img src="img.jpg" onerror="this.style.display='none';" />

Menggunakan JavaScript Eksternal:

var images = document.querySelectorAll('img');

for (var i = 0; i < images.length; i++) {
  images[i].onerror = function() {
    this.style.display='none';
  }
}
<img src='img.jpg' />

Menggunakan JavaScript Eksternal Modern:

document.querySelectorAll('img').forEach((img) => {
  img.onerror = function() {
    this.style.display = 'none';
  }
});
<img src='img.jpg' />

Lihat dukungan browser untuk fungsi NoteList.forEach dan panah .


1
Saya telah menemukan ini sebagai solusi paling andal bagi saya untuk masalah yang sangat mirip. Saya lebih suka tidak menunjukkan gambar apa pun daripada menunjukkan alternatif gambar yang rusak. Terima kasih.
pc_

Ini jelas tidak berfungsi jika Kebijakan Keamanan Konten melarang skrip sebaris.
isherwood

@isherwood Poin bagus. Saya telah menambahkan solusi yang berfungsi melalui file JS eksternal.
Nathan Arthur

11

Berikut adalah cara cepat dan kotor untuk mengganti semua gambar yang rusak, dan tidak perlu mengubah kode HTML;)

contoh codepen

    $("img").each(function(){
        var img = $(this);
        var image = new Image();
        image.src = $(img).attr("src");
        var no_image = "https://dummyimage.com/100x100/7080b5/000000&text=No+image";
        if (image.naturalWidth == 0 || image.readyState == 'uninitialized'){
            $(img).unbind("error").attr("src", no_image).css({
                height: $(img).css("height"),
                width: $(img).css("width"),
            });
        }
  });

9

Saya tidak dapat menemukan skrip yang sesuai dengan kebutuhan saya, jadi saya membuat fungsi rekursif untuk memeriksa gambar yang rusak dan berusaha memuatnya kembali setiap empat detik hingga diperbaiki.

Saya membatasinya menjadi 10 upaya seolah-olah itu tidak dimuat maka gambar mungkin tidak ada di server dan fungsinya akan memasuki infinite loop. Saya masih mengujinya. Jangan ragu untuk mengubahnya :)

var retries = 0;
$.imgReload = function() {
    var loaded = 1;

    $("img").each(function() {
        if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {

            var src = $(this).attr("src");
            var date = new Date();
            $(this).attr("src", src + "?v=" + date.getTime()); //slightly change url to prevent loading from cache
            loaded =0;
        }
    });

    retries +=1;
    if (retries < 10) { // If after 10 retries error images are not fixed maybe because they
                        // are not present on server, the recursion will break the loop
        if (loaded == 0) {
            setTimeout('$.imgReload()',4000); // I think 4 seconds is enough to load a small image (<50k) from a slow server
        }
        // All images have been loaded
        else {
            // alert("images loaded");
        }
    }
    // If error images cannot be loaded  after 10 retries
    else {
        // alert("recursion exceeded");
    }
}

jQuery(document).ready(function() {
    setTimeout('$.imgReload()',5000);
});

Ide bagus dengan mencoba memuat ulang gambar. Ini berguna untuk gambar yang diunggah / di-autogenerasi dan server mungkin tidak mendapatkan / selesai saat halaman dimuat. Itu beberapa format asli. Agak terlalu tidak konsisten dan tidak sesuai dengan selera saya ...
Joakim

8

Ini adalah teknik yang jelek, tapi cukup dijamin:

<img ...  onerror="this.parentNode.removeChild(this);">

6

Anda dapat menggunakan pengambilan GitHub sendiri untuk ini:

Frontend: https://github.com/github/fetch
atau untuk Backend, versi Node.js: https://github.com/bitinn/node-fetch

fetch(url)
  .then(function(res) {
    if (res.status == '200') {
      return image;
    } else {
      return placeholder;
    }
  }

Sunting: Metode ini akan menggantikan XHR dan seharusnya sudah ada di Chrome. Untuk siapa pun yang membaca ini di masa mendatang, Anda mungkin tidak perlu menyertakan perpustakaan yang disebutkan di atas.


6

Ini JavaScript, harus kompatibel lintas browser, dan dikirim tanpa markup jelek onerror="":

var sPathToDefaultImg = 'http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png',
    validateImage = function( domImg ) {
        oImg = new Image();
        oImg.onerror = function() {
            domImg.src = sPathToDefaultImg;
        };
        oImg.src = domImg.src;
    },
    aImg = document.getElementsByTagName( 'IMG' ),
    i = aImg.length;

while ( i-- ) {
    validateImage( aImg[i] );
}

CODEPEN:


upvote forwhile (i--)
s3c

4

Lebih baik menggunakan panggilan

jQuery(window).load(function(){
    $.imgReload();
});

Karena menggunakan document.readytidak perlu menyiratkan bahwa gambar dimuat, hanya HTML. Dengan demikian, tidak perlu untuk panggilan yang tertunda.


4

CoffeeScriptVarian :

Saya membuatnya untuk memperbaiki masalah dengan Turbolinks yang menyebabkan metode .error () muncul di Firefox kadang-kadang meskipun gambarnya benar-benar ada.

$("img").error ->
  e = $(@).get 0
  $(@).hide() if !$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)

4

Dengan menggunakan jawaban Prestaul , saya menambahkan beberapa cek dan saya lebih suka menggunakan cara jQuery.

<img src="image1.png" onerror="imgError(this,1);"/>
<img src="image2.png" onerror="imgError(this,2);"/>

function imgError(image, type) {
    if (typeof jQuery !== 'undefined') {
       var imgWidth=$(image).attr("width");
       var imgHeight=$(image).attr("height");

        // Type 1 puts a placeholder image
        // Type 2 hides img tag
        if (type == 1) {
            if (typeof imgWidth !== 'undefined' && typeof imgHeight !== 'undefined') {
                $(image).attr("src", "http://lorempixel.com/" + imgWidth + "/" + imgHeight + "/");
            } else {
               $(image).attr("src", "http://lorempixel.com/200/200/");
            }
        } else if (type == 2) {
            $(image).hide();
        }
    }
    return true;
}

4

Jika Anda telah memasukkan Anda imgdengan innerHTML, seperti: $("div").innerHTML = <img src="wrong-uri">, Anda dapat memuat gambar lain jika gagal melakukan, misalnya, ini:

<script>
    function imgError(img) {
        img.error="";
        img.src="valid-uri";
    }
</script>

<img src="wrong-uri" onerror="javascript:imgError(this)">

Mengapa javascript: _dibutuhkan? Karena skrip yang disuntikkan ke DOM melalui tag skrip dalam innerHTMLtidak berjalan pada saat disuntikkan, jadi Anda harus eksplisit.


4

Saya menemukan posting ini sambil melihat posting SO lainnya ini . Di bawah ini adalah salinan dari jawaban yang saya berikan di sana.

Saya tahu ini adalah utas lama, tetapi Bereaksi menjadi populer dan, mungkin, seseorang yang menggunakan Bereaksi akan datang ke sini mencari jawaban untuk masalah yang sama.

Jadi, jika Anda menggunakan React, Anda dapat melakukan sesuatu seperti di bawah ini, yang merupakan jawaban asli yang diberikan oleh Ben Alpert dari tim React di sini

getInitialState: function(event) {
    return {image: "http://example.com/primary_image.jpg"};
},
handleError: function(event) {
    this.setState({image: "http://example.com/failover_image.jpg"});
},
render: function() {
    return (
        <img onError={this.handleError} src={src} />;
    );
}

4

Saya membuat biola untuk mengganti gambar yang rusak menggunakan acara "onerror". Ini dapat membantu Anda.

    //the placeholder image url
    var defaultUrl = "url('https://sadasd/image02.png')";

    $('div').each(function(index, item) {
      var currentUrl = $(item).css("background-image").replace(/^url\(['"](.+)['"]\)/, '$1');
      $('<img>', {
        src: currentUrl
      }).on("error", function(e) {
        $this = $(this);
        $this.css({
          "background-image": defaultUrl
        })
        e.target.remove()
      }.bind(this))
    })

4

Berikut adalah contoh menggunakan objek Gambar HTML5 yang dibungkus oleh JQuery. Panggil fungsi pemuatan untuk URL gambar utama dan jika pemuatan itu menyebabkan kesalahan, ganti atribut src dari gambar dengan URL cadangan.

function loadImageUseBackupUrlOnError(imgId, primaryUrl, backupUrl) {
    var $img = $('#' + imgId);
    $(new Image()).load().error(function() {
        $img.attr('src', backupUrl);
    }).attr('src', primaryUrl)
}

<img id="myImage" src="primary-image-url"/>
<script>
    loadImageUseBackupUrlOnError('myImage','primary-image-url','backup-image-url');
</script>

4

JS murni. Tugas saya adalah: jika gambar 'bl-once.png' kosong -> masukkan yang pertama (yang tidak memiliki status 404) gambar dari daftar array (dalam direktori saat ini):

<img src="http://localhost:63342/GetImage/bl-once.png" width="200" onerror="replaceEmptyImage.insertImg(this)">

Mungkin perlu ditingkatkan, tetapi:

var srcToInsertArr = ['empty1.png', 'empty2.png', 'needed.png', 'notActual.png']; // try to insert one by one img from this array
    var path;
    var imgNotFounded = true; // to mark when success

    var replaceEmptyImage = {
        insertImg: function (elem) {

            if (srcToInsertArr.length == 0) { // if there are no more src to try return
                return "no-image.png";
            }
            if(!/undefined/.test(elem.src)) { // remember path
                path = elem.src.split("/").slice(0, -1).join("/"); // "http://localhost:63342/GetImage"
            }
            var url = path + "/" + srcToInsertArr[0];

            srcToInsertArr.splice(0, 1); // tried 1 src

            
                if(imgNotFounded){ // while not success
                    replaceEmptyImage.getImg(url, path, elem); // CALL GET IMAGE
                }
            

        },
        getImg: function (src, path, elem) { // GET IMAGE

            if (src && path && elem) { // src = "http://localhost:63342/GetImage/needed.png"
                
                var pathArr = src.split("/"); // ["http:", "", "localhost:63342", "GetImage", "needed.png"]
                var name = pathArr[pathArr.length - 1]; // "needed.png"

                xhr = new XMLHttpRequest();
                xhr.open('GET', src, true);
                xhr.send();

                xhr.onreadystatechange = function () {

                    if (xhr.status == 200) {
                        elem.src = src; // insert correct src
                        imgNotFounded = false; // mark success
                    }
                    else {
                        console.log(name + " doesn't exist!");
                        elem.onerror();
                    }

                }
            }
        }

    };

Jadi, itu akan memasukkan 'diperlukan.png' yang benar ke src saya atau 'no-image.png' dari dir saat ini.


Saya telah menggunakan situs yang sama. Ini hanya ide. Kode saya yang sebenarnya telah ditingkatkan ...
Дмитрий Дорогонов

3

Saya tidak yakin apakah ada cara yang lebih baik, tapi saya bisa memikirkan hack untuk mendapatkannya - Anda bisa Ajax memposting ke URL img, dan mengurai respons untuk melihat apakah gambar benar-benar kembali. Jika kembali sebagai 404 atau sesuatu, maka tukar keluar img. Meskipun saya berharap ini sangat lambat.


3

Saya memecahkan masalah saya dengan dua fungsi sederhana ini:

function imgExists(imgPath) {
    var http = jQuery.ajax({
                   type:"HEAD",
                   url: imgPath,
                   async: false
               });
    return http.status != 404;
}

function handleImageError() {
    var imgPath;

    $('img').each(function() {
        imgPath = $(this).attr('src');
        if (!imgExists(imgPath)) {
            $(this).attr('src', 'images/noimage.jpg');
        }
    });
}

3

jQuery 1.8

// If missing.png is missing, it is replaced by replacement.png
$( "img" )
  .error(function() {
    $( this ).attr( "src", "replacement.png" );
  })
  .attr( "src", "missing.png" );

jQuery 3

// If missing.png is missing, it is replaced by replacement.png
$( "img" )
  .on("error", function() {
    $( this ).attr( "src", "replacement.png" );
  })
  .attr( "src", "missing.png" );

referensi


3

Saya rasa saya memiliki cara yang lebih elegan dengan delegasi acara dan event menangkap di window's errorbahkan ketika gambar cadangan gagal untuk beban.

img {
  width: 100px;
  height: 100px;
}
<script>
  window.addEventListener('error', windowErrorCb, {
    capture: true
  }, true)

  function windowErrorCb(event) {
    let target = event.target
    let isImg = target.tagName.toLowerCase() === 'img'
    if (isImg) {
      imgErrorCb()
      return
    }

    function imgErrorCb() {
      let isImgErrorHandled = target.hasAttribute('data-src-error')
      if (!isImgErrorHandled) {
        target.setAttribute('data-src-error', 'handled')
        target.src = 'backup.png'
      } else {
        //anything you want to do
        console.log(target.alt, 'both origin and backup image fail to load!');
      }
    }
  }
</script>
<img id="img" src="error1.png" alt="error1">
<img id="img" src="error2.png" alt="error2">
<img id="img" src="https://i.stack.imgur.com/ZXCE2.jpg" alt="avatar">

Intinya adalah :

  1. Masukkan kode ke dalam headdan dieksekusi sebagai skrip inline pertama. Jadi, itu akan mendengarkan kesalahan yang terjadi setelah skrip.

  2. Gunakan menangkap peristiwa untuk menangkap kesalahan, terutama untuk peristiwa yang tidak menggelembung.

  3. Gunakan delegasi acara yang menghindari peristiwa mengikat pada setiap gambar.

  4. Berikan imgelemen kesalahan atribut setelah memberi mereka a backup.pnguntuk menghindari hilangnya backup.pngloop tak terhingga dan selanjutnya seperti di bawah ini:

img error-> backup.png-> error-> backup.png-> error -> ,,,,,


Sejauh ini, ini adalah jawaban terbaik. Satu-satunya hal yang saya sarankan adalah menggunakan let isImgErrorHandled = target.src === 'backup.png';karena menyederhanakan sedikit.
Sabo

@ Sabo, Ada sedikit masalah karena jalur src mungkin tidak sama dengan jalur yang saya tetapkan. Misalnya,, target.src='backup.png'tapi lain kali console.log(target.src)mungkin tidakbackup.png
xianshenglu

2
;(window.jQuery || window.Zepto).fn.fallback = function (fallback) {
    return this.one('error', function () {
        var self = this;
        this.src = (fallback || 'http://lorempixel.com/$width/$height')
        .replace(/\$(\w+)/g, function (m, t) { return self[t] || ''; });
    });
};

Anda dapat melewati jalur placeholder dan mengakses semua properti dari objek gambar yang gagal melalui $*:

$('img').fallback('http://dummyimage.com/$widthx$height&text=$src');

http://jsfiddle.net/ARTsinn/Cu4Zn/


2

Ini telah membuat saya frustasi selama bertahun-tahun. Perbaikan CSS saya menetapkan gambar latar belakang pada img. Saat gambar dinamis srctidak dimuat ke latar depan, placeholder terlihat imgdi bg. Ini berfungsi jika gambar Anda memiliki ukuran default (misalnya height, min-height, widthdan / atau min-width).

Anda akan melihat ikon gambar yang rusak tetapi ini merupakan peningkatan. Diuji ke IE9 berhasil. iOS Safari dan Chrome bahkan tidak menampilkan ikon yang rusak.

.dynamicContainer img {
  background: url('/images/placeholder.png');
  background-size: contain;
}

Tambahkan sedikit animasi untuk memberi srcwaktu memuat tanpa flicker latar belakang. Chrome memudar di latar belakang dengan lancar tetapi desktop Safari tidak.

.dynamicContainer img {
  background: url('/images/placeholder.png');
  background-size: contain;
  -webkit-animation: fadein 1s;
  animation: fadein 1s;                     
}

@-webkit-keyframes fadein {
  0%   { opacity: 0.0; }
  50%  { opacity: 0.5; }
  100% { opacity: 1.0; }
}

@keyframes fadein {
  0%   { opacity: 0.0; }
  50%  { opacity: 0.5; }
  100% { opacity: 1.0; }
}

2

Jika gambar tidak dapat dimuat (misalnya, karena tidak ada di URL yang disediakan), URL gambar akan diubah menjadi default,

Untuk selengkapnya tentang .error ()

$('img').on('error', function (e) {
  $(this).attr('src', 'broken.png');
});


1

Saya mendapat masalah yang sama. Kode ini berfungsi dengan baik pada kasus saya.

// Replace broken images by a default img
$('img').each(function(){
    if($(this).attr('src') === ''){
      this.src = '/default_feature_image.png';
    }
});

1

Terkadang menggunakan erroracara tersebut tidak layak, misalnya karena Anda mencoba melakukan sesuatu pada halaman yang sudah dimuat, seperti ketika Anda menjalankan kode melalui konsol, bookmarklet, atau skrip yang dimuat secara tidak sinkron. Dalam hal itu, periksa itu img.naturalWidthdanimg.naturalHeight 0 sepertinya melakukan trik.

Misalnya, inilah cuplikan untuk memuat ulang semua gambar yang rusak dari konsol:

$$("img").forEach(img => {
  if (!img.naturalWidth && !img.naturalHeight) {
    img.src = img.src;
  }
}

0

Saya menemukan ini berfungsi paling baik, jika ada gambar gagal memuat pertama kali, itu sepenuhnya dihapus dari DOM. Eksekusi console.clear()menjaga jendela konsol tetap bersih, karena kesalahan 404 tidak dapat dihilangkan dengan blok coba / tangkap.

$('img').one('error', function(err) {
    // console.log(JSON.stringify(err, null, 4))
    $(this).remove()
    console.clear()
})
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.