Mendeteksi saat gambar gagal dimuat di Javascript

105

Apakah ada cara untuk menentukan apakah jalur gambar mengarah ke gambar yang sebenarnya, yaitu mendeteksi ketika gambar gagal dimuat di Javascript.

Untuk aplikasi web, saya mengurai file xml dan secara dinamis membuat gambar HTML dari daftar jalur gambar. Beberapa jalur gambar mungkin tidak lagi ada di server, jadi saya ingin gagal dengan baik dengan mendeteksi gambar mana yang gagal dimuat dan menghapus elemen img HTML itu.

Catatan solusi JQuery tidak akan dapat digunakan (bos tidak ingin menggunakan JQuery, ya saya tahu jangan mulai saya). Saya tahu cara di JQuery untuk mendeteksi saat gambar dimuat, tetapi tidak mengetahui apakah gambar tersebut gagal.

Kode saya untuk membuat elemen img tetapi bagaimana saya bisa mendeteksi jika jalur img mengarah ke gambar yang gagal dimuat?

var imgObj = new Image();  // document.createElement("img");
imgObj.src = src;
sazr
sumber
Ini mungkin membantu Anda: stackoverflow.com/questions/1977871/… (ini jQuery, tetapi masih dapat membawa Anda ke jalur yang benar)
Ben Lee
coba salah satu dari google.com/…
ajax333221
2
Lucu @ ajax333221 pertanyaan ini adalah yang pertama di hasil tautan Anda :)
SSH Ini
tulis pemilih JQuery untuk menemukan Bos baru ... internet adalah tempat yang hebat.
JJS

Jawaban:

116

Anda bisa mencoba kode berikut. Saya tidak dapat menjamin kompatibilitas browser, jadi Anda harus mengujinya.

function testImage(URL) {
    var tester=new Image();
    tester.onload=imageFound;
    tester.onerror=imageNotFound;
    tester.src=URL;
}

function imageFound() {
    alert('That image is found and loaded');
}

function imageNotFound() {
    alert('That image was not found.');
}

testImage("http://foo.com/bar.jpg");

Dan simpati saya untuk bos tahan jQuery!

Nikhil
sumber
2
Adakah ide jika ada cara untuk mengetahui apakah itu menemui pengalihan?
quickshiftin
4
Ini tidak berfungsi di webKit (Epiphany, Safari, ...) tergantung pada server tempat Anda mendapatkan gambar. Misalnya, terkadang imgur tidak mengirim gambar yang ada atau berstatus 404 dan peristiwa kesalahan tidak dipicu dalam kasus ini.
Masalah dengan ini adalah pesan Anda, "Gambar itu tidak ditemukan." Kode respons bisa jadi 500 atau 403 atau yang lainnya. Anda tidak tahu bahwa itu adalah 404. Faktanya, kemungkinan besar itu bukan 404 karena Anda mungkin tidak akan mencoba dan memuat gambar yang tidak ada.
PHP Guru
1
harus menambahkan event handler alih-alih
asignment
50

Jawabannya bagus, tapi ini menimbulkan satu masalah. Setiap kali Anda menetapkan onloadatau onerrorsecara langsung, itu mungkin menggantikan panggilan balik yang telah ditetapkan sebelumnya. Itulah mengapa ada metode bagus yang "mendaftarkan pendengar yang ditentukan di EventTarget tempat itu dipanggil" seperti yang mereka katakan di MDN . Anda dapat mendaftarkan pendengar sebanyak yang Anda inginkan di acara yang sama.

Izinkan saya menulis ulang jawabannya sedikit.

function testImage(url) {
    var tester = new Image();
    tester.addEventListener('load', imageFound);
    tester.addEventListener('error', imageNotFound);
    tester.src = url;
}

function imageFound() {
    alert('That image is found and loaded');
}

function imageNotFound() {
    alert('That image was not found.');
}

testImage("http://foo.com/bar.jpg");

Karena proses pemuatan sumber daya eksternal tidak sinkron, akan lebih baik jika menggunakan JavaScript modern dengan promise, seperti berikut ini.

function testImage(url) {

    // Define the promise
    const imgPromise = new Promise(function imgPromise(resolve, reject) {

        // Create the image
        const imgElement = new Image();

        // When image is loaded, resolve the promise
        imgElement.addEventListener('load', function imgOnLoad() {
            resolve(this);
        });

        // When there's an error during load, reject the promise
        imgElement.addEventListener('error', function imgOnError() {
            reject();
        })

        // Assign URL
        imgElement.src = url;

    });

    return imgPromise;
}

testImage("http://foo.com/bar.jpg").then(

    function fulfilled(img) {
        console.log('That image is found and loaded', img);
    },

    function rejected() {
        console.log('That image was not found');
    }

);
emil.c
sumber
2
mungkin saya melewatkan sesuatu, tetapi bagaimana tugas (tester.onload = ..) menggantikan panggilan balik, jika "penguji" baru saja dibuat? bahkan jika beberapa bagian kode yang tidak jelas menambahkan peristiwa ke setiap gambar yang dibuat, tidak jelas bahwa kami ingin menyimpan peristiwa tersebut untuk tujuan mendeteksi jika gambar ada.
jvilhena
1
Anda benar sekali. Dalam kasus khusus ini mungkin tidak menjadi masalah karena kemungkinan besar tidak akan diganti. Namun, secara umum, menambahkan event listener adalah praktik yang lebih baik daripada menetapkan metode secara langsung.
emil.c
1
Fungsi @JohnWeisz Panah anonim, oleh karena itu lebih sulit untuk men-debug, gunakan dengan hati-hati.
emil.c
10
@GifCo Saya merasa tidak nyaman melanjutkan diskusi seperti itu dengan Anda. Saya merasa tersinggung dengan bahasa Anda. Jika Anda yakin jawaban saya salah atau tidak lengkap, sarankan perubahan dan jelaskan alasan Anda. Jika menurut Anda ada sesuatu yang BURUK, sarankan praktik yang baik dengan jawaban Anda sendiri.
emil.c
2
Mengapa ada diskusi tentang fungsi panah di sini? Ini di luar topik. Jawabannya baik-baik saja karena browser lama tidak mendukung fungsi panah (Internet Explorer misalnya).
PHP Guru
29

Ini:

<img onerror="this.src='/images/image.png'" src="...">
Rafael Martins
sumber
1
Meskipun ini adalah atribut berguna yang dapat digunakan sebagai teknik pengalihan gambar, respons yang lebih bertele-tele akan membantu pembaca untuk memahaminya.
sorak
1
Sangat singkat dan sangat berguna! Untuk menyembunyikannya:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM
2
Komentar @ sorak membuatku tertawa jijik. Ini jawaban yang benar.
pengguna3751385
@ J0ANMM Cara lain untuk menyembunyikan gambar adalah dengan menambahkan atribut alt kosong: <img alt = "" src = "yourpicture.png">
Rick Glimmer
Luar biasa! Alih-alih gagal ke gambar, saya mencetak teks ini onerror = "this.alt = 'Gambar Tidak Valid, Gunakan Tautan ^'"
berkeringat
6
/**
 * Tests image load.
 * @param {String} url
 * @returns {Promise}
 */
function testImageUrl(url) {
  return new Promise(function(resolve, reject) {
    var image = new Image();
    image.addEventListener('load', resolve);
    image.addEventListener('error', reject);
    image.src = url;
  });
}

return testImageUrl(imageUrl).then(function imageLoaded(e) {
  return imageUrl;
})
.catch(function imageFailed(e) {
  return defaultImageUrl;
});
holmberd.dll
sumber
4

jQuery + CSS untuk img

Dengan jQuery, ini berfungsi untuk saya:

$('img').error(function() {
    $(this).attr('src', '/no-img.png').addClass('no-img');
});

Dan saya dapat menggunakan gambar ini di mana pun di situs web saya terlepas dari ukurannya dengan properti CSS3 berikut:

img.no-img {
    object-fit: cover;
    object-position: 50% 50%;
}

TIPS 1: gunakan gambar persegi berukuran minimal 800 x 800 piksel.

TIPS 2: untuk digunakan dengan potret orang , gunakanobject-position: 20% 50%;

CSS hanya untuk background-img

Untuk gambar latar belakang yang hilang, saya juga menambahkan yang berikut pada setiap background-imagedeklarasi:

background-image: url('path-to-image.png'), url('no-img.png');

CATATAN: tidak berfungsi untuk gambar transparan.

Sisi server Apache

Solusi lain adalah mendeteksi gambar yang hilang dengan Apache sebelum dikirim ke browser dan menggantinya dengan konten default no-img.png.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} /images/.*\.(gif|jpg|jpeg|png)$
RewriteRule .* /images/no-img.png [L,R=307]
Meloman
sumber
3

Berikut adalah fungsi yang saya tulis untuk jawaban lain: Verifikasi Url Gambar Javascript . Saya tidak tahu apakah itu apa yang Anda butuhkan, tetapi menggunakan berbagai teknik yang Anda akan menggunakan yang meliputi penangan untuk onload, onerror, onabortdan timeout umum.

Karena pemuatan gambar tidak sinkron, Anda memanggil fungsi ini dengan gambar Anda dan kemudian memanggil panggilan balik Anda beberapa saat kemudian dengan hasilnya.

jfriend00
sumber
-19

seperti di bawah ini:

var img = new Image(); 
img.src = imgUrl; 

if (!img.complete) {

//has picture
}
else //not{ 

}
JamesChen
sumber
3
Nggak. Ini mungkin memberi petunjuk kepada Anda apakah gambar di-cache atau tidak, di beberapa browser - tetapi tanpa load callback, Anda tidak akan menunggu bahkan untuk memberi browser kesempatan untuk memulai permintaan HTTP untuk gambar itu.
ChaseMoskal
ini hanya untuk mengatakan sesuatu!
Hitmands
4
Pemuatan gambar tidak sinkron.
emil.c
@ emil.c tidak selalu, untuk beberapa alasan. ChaseMoskal (yang SO tidak mengizinkan saya memberi tahu ...) benar - ini hanya berfungsi jika gambar selesai dimuat sebelum eksekusi JS dilanjutkan, yang tampaknya terjadi setiap kali di-cache.
tristan