Визначте, коли зображення не завантажується у Javascript


104

Чи є спосіб визначити, чи веде шлях зображення до фактичного зображення, тобто виявити, коли зображення не завантажується в Javascript.

Для веб-програми я розбираю XML-файл і динамічно створюю HTML-зображення із списку шляхів зображення. Деякі контури зображень можуть більше не існувати на сервері, тому я хочу вийти з ладу, виявивши, які зображення не завантажуються та видаливши цей елемент імгнення HTML.

Зверніть увагу, що рішення JQuery не можуть бути використані (бос не хоче використовувати JQuery, так, я знаю, не запускайте мене). Я знаю спосіб у JQuery виявити, коли завантажується зображення, але не те, чи не вдалося.

Мій код для створення елементів img, але як я можу виявити, якщо шлях img призводить до невдалого завантаження зображення?

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

Це може допомогти вам: stackoverflow.com/questions/1977871/… (це jQuery, але це все ще може привести вас на правильний шлях)
Бен Лі

спробуйте один із цих google.com/…
ajax333221

2
Смішно @ ajax333221 саме це питання є першим в результатах вашого посилання :)
SSH Це

напишіть селектор JQuery, щоб знайти нового Boss ... Інтернет - це велике місце.
JJS

Відповіді:


115

Ви можете спробувати наступний код. Я не можу поручити сумісність браузера, тому вам доведеться перевірити це.

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

І мої симпатії до шефа, стійкого до jQuery!


2
Будь-яка ідея, чи є спосіб сказати, чи виникає переспрямування?
швидкий зміна

4
Це не працює на webKit (Epiphany, Safari, ...) залежно від сервера, з якого ви отримуєте зображення. Наприклад, іноді imgur не надсилає зображення, яке існує, ані статус 404, і в цьому випадку подія помилки не спрацьовує.

Проблема з цим полягає у вашому повідомленні "Це зображення не знайдено". Код відповіді може бути 500 або 403 або щось інше. Ви не знаєте, що це було 404. Насправді це не дуже ймовірно, що це 404, оскільки ви, ймовірно, не намагалися б завантажити зображення, яке там немає.
Гуру PHP

1
слід додати обробник подій замість прямого призначення
cdalxndr

50

Відповідь хороша, але вона вводить одну проблему. Щоразу, коли ви призначаєте onloadабо onerrorбезпосередньо, він може замінювати зворотний дзвінок, який був призначений раніше. Ось чому є приємний метод, який "реєструє вказаного слухача на EventTarget, на який він викликається", як кажуть на MDN . Ви можете зареєструвати стільки слухачів, скільки хочете на одній події.

Дозвольте мені трохи переписати відповідь.

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

Оскільки процес завантаження зовнішніх ресурсів асинхронний, було б навіть приємніше використовувати сучасний JavaScript з обіцянками, такими як наступні.

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
можливо, мені щось не вистачає, але як призначення може (тестер.onload = ..) замінити зворотний виклик, якщо "тестер" був тільки створений? навіть якщо якась незрозуміла частина коду додає подію до кожного створеного зображення, не очевидно, що ми хочемо зберегти ці події з метою виявлення наявності зображення.
jvilhena

1
Ви абсолютно праві. У цьому конкретному випадку це може не бути проблемою, оскільки велика ймовірність, що його не замінять. Однак, як правило, додавання слухача подій є кращою практикою, ніж призначення методу безпосередньо.
emil.c

1
@JohnWeisz Стрілки є анонімними, тому важче відладкувати, використовуйте їх обережно.
emil.c

10
@GifCo Мені не комфортно продовжувати з вами таку дискусію. Я почуваюсь ображеною на вашу мову. Якщо ви вважаєте, що моя відповідь неправильна або неповна, запропонуйте зміни та поясніть свої міркування. Якщо ви вважаєте, що щось є BAD практикою, запропонуйте гарну практику з власною відповіддю.
emil.c

2
Чому тут обговорюються функції стрілок? Це поза темою. Відповідь гарна, як це особливо, оскільки старі браузери не підтримують функції стрілок (наприклад, Internet Explorer).
Гуру PHP

29

Це:

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

1
Незважаючи на те, що це корисний атрибут, який може бути використаний як техніка відмови від зображень, читачам буде корисно зрозуміти більш детальну відповідь.
сорак

1
Так коротко і так корисно! Щоб просто приховати це:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM

2
@ коментар сорака змусив мене сміятися від огиди. Це правильна відповідь.
user3751385

@ J0ANMM Ще один спосіб приховати зображення - додати порожній атрибут alt: <img alt = "" src = "yourpicture.png">
Rick Glimmer

Відмінно! Замість переходу до зображення я надрукую цей текст onerror = "this.alt = 'Недійсне зображення, використовуйте посилання ^'"
потужно

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

jQuery + CSS для img

З jQuery це працює для мене:

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

І я можу використовувати це зображення скрізь на своєму веб-сайті незалежно від його розміру із наступним властивістю CSS3:

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

Порада 1: використовуйте квадратне зображення розміром не менше 800 х 800 пікселів.

Порада 2: для використання з портретом людей , використовуйтеobject-position: 20% 50%;

CSS лише для background-img

Для відсутніх фонових зображень я також додав у кожну background-imageдекларацію наступне :

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

ПРИМІТКА: не працює для прозорих зображень.

Сторона сервера Apache

Іншим рішенням є виявлення відсутнього зображення за допомогою Apache, перш ніж надсилати його в браузер і замінювати його за замовчуванням no-img.png.

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

3

Ось функцію, яку я написав для іншої відповіді: Javascript URL Urli Verify . Я не знаю , якщо це саме те , що вам потрібно, але він використовує різні методи , які ви могли б використовувати , які включають в себе обробник onload, onerror, onabortі загальний тайм - аут.

Оскільки завантаження зображення асинхронне, ви викликаєте цю функцію зі своїм зображенням, а потім вона викликає зворотний дзвінок десь пізніше з результатом.


-19

так само, як нижче:

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

if (!img.complete) {

//has picture
}
else //not{ 

}

3
Ні. Це може підказати вам на те, чи кеширується зображення в деяких браузерах, але без зворотного виклику завантаження ви не чекаєте навіть хвилини, щоб дати браузеру можливість ініціювати HTTP-запит на це зображення.
ChaseMoskal

це просто для того, щоб щось сказати!
Hitmands

4
Завантаження зображень асинхронне.
emil.c

@ emil.c це не завжди, чомусь. ChaseMoskal (якому ТАК не дасть мені сповістити ...) має право - це працює лише в тому випадку, якщо зображення закінчується завантаженням до того, як триває виконання JS, що, здається, відбувається щоразу, коли воно кешоване.
тристан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.