Определить, когда изображение не загружается в Javascript


105

Есть ли способ определить, ведет ли путь к изображению к фактическому изображению, т.е. определить, когда изображение не загружается в Javascript.

Для веб-приложения я анализирую файл xml и динамически создаю HTML-изображения из списка путей к изображениям. Некоторые пути к изображениям могут больше не существовать на сервере, поэтому я хочу корректно завершить работу, определив, какие изображения не загружаются, и удалив этот элемент HTML img.

Обратите внимание, что решения 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 This

напишите селектор JQuery, чтобы найти нового Босса ... Интернет - огромное место.
JJS

Ответы:


116

Вы можете попробовать следующий код. Я не могу поручиться за совместимость с браузером, поэтому вам придется это проверить.

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
Есть идеи, есть ли способ узнать, сталкивается ли он с перенаправлением?
quickshiftin

4
Это не работает на webKit (Epiphany, Safari, ...) в зависимости от сервера, с которого вы получаете изображение. Например, иногда imgur не отправляет существующее изображение или статус 404, и в этом случае не запускается событие ошибки.

Проблема заключается в вашем сообщении «Это изображение не найдено». Код ответа может быть 500, 403 или что-то еще. Вы не знаете, что это был 404. На самом деле, маловероятно, что это был 404, поскольку вы, вероятно, не стали бы пытаться загрузить изображение, которого там нет.
PHP Guru

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

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

1
@JohnWeisz Arrow функции анонимны, поэтому их сложнее отлаживать, используйте их осторожно.
emil.c

10
@GifCo Мне неудобно продолжать такое обсуждение с вами. Меня обижает твой язык. Если вы считаете, что мой ответ неправильный или неполный, предложите изменения и объясните свои доводы. Если вы считаете, что что-то является ПЛОХОЙ практикой, предложите хорошую практику своим собственным ответом.
emil.c

2
Почему здесь обсуждают стрелочные функции? Это не по теме. Ответ хорош, тем более, что старые браузеры не поддерживают функции стрелок (например, Internet Explorer).
PHP Guru

30

Это:

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

1
Хотя это полезный атрибут, который можно использовать в качестве метода отработки отказа изображения, более подробный ответ может помочь читателям понять его.
sorak

2
Так коротко и так полезно! Чтобы просто скрыть это:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM

2
Комментарий @sorak заставил меня смеяться от отвращения. Это правильный ответ.
user3751385

@ J0ANMM Другой способ скрыть изображение - добавить пустой атрибут alt: <img alt = "" src = "yourpicture.png">
Рик

Превосходно! Вместо перехода к изображению я печатаю этот текст onerror = "this.alt = 'Not Valid Image, Use Link ^'"
потный

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 x 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 Image Url 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 (которого SO не позволяет мне уведомить ...) прав - это работает только в том случае, если изображение завершает загрузку до продолжения выполнения JS, что, кажется, происходит всякий раз, когда оно кэшируется.
Тристан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.