Javascript'te bir görüntünün yüklenemediğini algılama


105

Bir görüntü yolunun gerçek bir görüntüye yol açıp açmadığını belirlemenin bir yolu var mı, yani bir görüntünün Javascript'e yüklenemediğini tespit et.

Bir web uygulaması için, bir xml dosyasını ayrıştırıyorum ve bir görüntü yolu listesinden dinamik olarak HTML görüntüleri oluşturuyorum. Bazı görüntü yolları artık sunucuda mevcut olmayabilir, bu nedenle hangi görüntülerin yüklenemediğini tespit ederek ve bu HTML img öğesini silerek sorunsuzca başarısız olmak istiyorum.

Not JQuery çözümleri kullanılamayacak (patron JQuery'yi kullanmak istemiyor, evet, beni başlatmadığımı biliyorum). JQuery'de bir görüntünün ne zaman yüklendiğini algılamanın bir yolunu biliyorum, ancak başarısız olup olmadığını bilmiyorum.

Kodum img öğeleri oluşturmaya yöneliktir, ancak img yolunun görüntünün yüklenememesine yol açıp açmadığını nasıl tespit edebilirim?

var imgObj = new Image();  // document.createElement("img");
imgObj.src = src;

Bu size yardımcı olabilir: stackoverflow.com/questions/1977871/… (bu jQuery, ancak yine de sizi doğru yola götürebilir)
Ben Lee

bunlardan birini google.com/…
ajax333221

2
Komik @ ajax333221 bu soru, bağlantınızın sonuçlarında ilk sırada :)
SSH Bu

yeni bir Boss bulmak için bir JQuery seçici yazın ... internet büyük bir yer.
JJS

Yanıtlar:


116

Aşağıdaki kodu deneyebilirsiniz. Yine de tarayıcı uyumluluğunu garanti edemem, bu yüzden bunu test etmeniz gerekecek.

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");

Ve jQuery'ye dirençli patrona sempati duyuyorum!


2
Bir yönlendirme ile karşılaşıp karşılaşmadığını anlamanın bir yolu olup olmadığına dair bir fikriniz var mı?
quickshift

4
Bu, görüntü aldığınız sunucuya bağlı olarak webKit'te (Epiphany, Safari, ...) çalışmaz. Örneğin, bazen imgur var olan bir görüntüyü veya bir 404 durumunu göndermez ve bu durumda hata olayı tetiklenmez.

Bununla ilgili sorun, "Bu görüntü bulunamadı" mesajınızdır. Yanıt kodu 500 veya 403 veya başka bir şey olabilir. Bunun bir 404 olduğunu bilmiyorsunuz. Aslında 404 olması pek olası değil çünkü muhtemelen orada olmayan bir görüntüyü yüklemeye çalışmayacaksınız.
PHP Guru

1
doğrudan sıralama yerine olay işleyicisi eklemeli
cdalxndr

50

Cevap güzel, ancak bir sorunu ortaya çıkarıyor. Ne zaman atarsanız onloadveya onerrordoğrudan atarsanız , daha önce atanan geri aramanın yerini alabilir. Bu güzel bir yöntem var nedeni budur "kayıtları bunun üzerine denir eventtarget belirtilen dinleyici" olarak da söylemek MDN'yi . Aynı etkinliğe istediğiniz kadar dinleyici kaydedebilirsiniz.

Cevabı biraz yeniden yazayım.

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");

Harici kaynak yükleme işlemi eşzamansız olduğundan, modern JavaScript'i aşağıdakiler gibi vaatlerle kullanmak daha da güzel olurdu.

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');
    }

);

2
belki bir şeyi kaçırıyorum, ancak "test cihazı" yeni oluşturulmuşsa, atama (tester.onload = ..) nasıl bir geri aramayı değiştirebilir? Kodun belirsiz bir kısmı oluşturulan her görüntüye bir olay eklese bile, bir görüntünün var olup olmadığını tespit etmek amacıyla bu olayları saklamak istediğimiz açık değildir.
jvilhena

1
Kesinlikle haklısın. Bu özel durumda sorun olmayabilir, çünkü büyük olasılıkla değiştirilmeyecektir. Ancak, genel olarak, bir olay dinleyicisi eklemek, bir yöntemi doğrudan atamaktan daha iyi bir uygulamadır.
emil.c

1
@JohnWeisz Ok işlevleri anonimdir, bu nedenle hata ayıklamak daha zordur, dikkatli kullanın.
emil.c

10
@GifCo Seninle böyle bir tartışmaya devam ederken kendimi rahat hissetmiyorum. Dilinden rahatsız oluyorum. Cevabımın yanlış veya eksik olduğuna inanıyorsanız, değişiklik önerin ve gerekçenizi açıklayın. Bir şeyin KÖTÜ uygulama olduğunu düşünüyorsanız, kendi cevabınızla iyi bir uygulama önerin.
emil.c

2
Burada ok fonksiyonları hakkında neden bir tartışma var? Konu dışı. Cevap, özellikle eski tarayıcılar ok işlevlerini desteklemediğinden (örneğin Internet Explorer) olduğu gibi iyidir.
PHP Guru

30

Bu:

<img onerror="this.src='/images/image.png'" src="...">

1
Bu, bir görüntü yük devretme tekniği olarak kullanılabilecek yararlı bir özellik olsa da, okuyucuların bunu anlaması için daha ayrıntılı bir yanıt yardımcı olacaktır.
sorak

2
Çok kısa ve çok kullanışlı! Sadece gizlemek için:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM

2
@ sorak'ın yorumu beni tiksinti ile güldürdü. Bu doğru cevap.
user3751385

@ J0ANMM Görüntüyü gizlemenin bir başka yolu da boş bir alt özelliği eklemektir: <img alt = "" src = "yourpicture.png">
Rick Glimmer

Mükemmel! Bir resme devretmek yerine, bu metni onerror = "this.alt = 'Geçerli Değil Resim, Bağlantı Kullan ^'"
terli

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;
});

4

img için jQuery + CSS

JQuery ile bu benim için çalışıyor:

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

Ve bu resmi, aşağıdaki CSS3 özelliği ile boyutuna bakılmaksızın web sitemin her yerinde kullanabilirim:

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

İPUCU 1: En az 800 x 800 piksellik kare bir resim kullanın .

İPUCU 2: İnsanların portresiyle kullanmak içinobject-position: 20% 50%;

CSS yalnızca arka plan img için

Eksik arka plan resimleri için, her background-imagebildirime aşağıdakileri de ekledim :

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

NOT: şeffaf resimler için çalışmıyor.

Apache sunucu tarafı

Diğer bir çözüm, tarayıcıya göndermeden önce eksik görüntüyü Apache ile tespit etmek ve varsayılan no-img.png içeriği ile yeniden yerleştirmektir.

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

3

İşte başka bir cevap için yazdığım bir fonksiyon: Javascript Image Url Verify . Ben tam olarak neye ihtiyacınız olup olmadığını bilmiyorum, ama için işleyicileri içerir Kullanmak olacağını çeşitli teknikler kullanır onload, onerror, onabortve genel zaman aşımı.

Görüntü yükleme eşzamansız olduğundan, bu işlevi görüntünüzle çağırırsınız ve daha sonra sonuçla birlikte geri aramanızı çağırır.


-19

aynen aşağıdaki gibi:

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

if (!img.complete) {

//has picture
}
else //not{ 

}

3
Hayır! Bu, bazı tarayıcılarda görüntünün önbelleğe alınıp alınmadığı konusunda size ipucu verebilir - ancak bir yükleme geri araması olmadan, tarayıcıya o görüntü için bir HTTP isteği başlatma şansı vermek için bir an bile beklemiyorsunuz.
ChaseMoskal

bu sadece bir şey söylemek için!
Hitmands

4
Görüntü yükleme eşzamansızdır.
emil.c

@ emil.c nedense her zaman değil. ChaseMoskal (SO bildirmeme izin vermez ...) haklıydı - bu yalnızca görüntünün JS yürütmesi devam etmeden önce yüklenmesi biterse çalışır, bu da önbelleğe alındığında gerçekleşiyor gibi görünüyor.
tristan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.