JQuery / JavaScript, чтобы заменить сломанные изображения

502

У меня есть веб-страница, которая содержит кучу изображений. Иногда изображение недоступно, поэтому в браузере клиента отображается разбитое изображение.

Как я могу использовать jQuery для получения набора изображений, отфильтровать его на разбитые изображения, а затем заменить src?


- Я думал, что было бы проще сделать это с помощью jQuery, но оказалось, что гораздо проще просто использовать чистое решение JavaScript, то есть то, что предоставляется Prestaul.

Теги:
brokenimage

32 ответа

691
Лучший ответ

Обработайте событие onError, чтобы изображение переназначало исходный код с помощью JavaScript:

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

Или без функции JavaScript:

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

В следующей таблице совместимости перечислены браузеры, поддерживающие функцию ошибки:

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

  • 124
    Вы, вероятно, хотите очистить onerror перед установкой src. В противном случае, если noimage.gif также отсутствует, вы можете получить «переполнение стека».
  • 42
    Я думал и надеялся, что мы отошли от встроенных атрибутов для событий javascript ...
Показать ещё 20 комментариев
196

Я использую встроенный обработчик error:

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

error() устарел в 1.8 или новее.

  • 107
    Если вы используете эту технику, вы можете использовать метод "one", чтобы избежать необходимости отмены привязки события: $ ('img'). One ('error', function () {this.src = 'broken.gif';}) ;
  • 7
    +1 Но разве ты должен это развязать? Он прекрасно работает на динамических изображениях (например, тех, которые могут меняться при наведении), если вы не отсоединяете его.
Показать ещё 11 комментариев
117

В случае, если кто-то вроде меня, пытается привязать событие error к динамическому тегу HTML img, я хотел бы указать, что есть catch:

По-видимому, img события ошибок не пузырь в большинстве браузеров, вопреки тому, что стандарт.

Итак, что-то вроде следующего будет не работать:

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

Надеюсь, это будет полезно кому-то другому. Хотелось бы, чтобы я видел это здесь в этой теме. Но я этого не сделал. Итак, я добавляю его

  • 0
    та же проблема здесь, спасибо за указание на это
  • 0
    не работал Я загружаю мертвое изображение динамически и добавляю его в dom, и событие 'error' не вызывается.
Показать ещё 1 комментарий
53

Вот отдельное решение:

$(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
    Почти правильно ... правильное изображение в IE все равно будет возвращаться (typeof (this.naturalWidth) == "undefined") == true; - Я изменил оператор if на (! This.complete || (! $. Browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0)))
  • 3
    это правила, потому что он может обнаружить поврежденное изображение после загрузки страницы. мне это нужно
Показать ещё 3 комментария
31

Я считаю, что это то, что вам нужно: jQuery.Preload

Вот пример кода из демонстрации, вы указываете загрузочные и не найденные изображения, и все вы настроены:

$('#images img').preload({
    placeholder:'placeholder.jpg',
    notFound:'notfound.jpg'
});
  • 1
    jQuery.Preload - это плагин, который требуется для использования примера кода.
  • 16
    Да ... это связано с ответом в первой строке.
Показать ещё 1 комментарий
23
$(window).bind('load', function() {
$('img').each(function() {
    if((typeof this.naturalWidth != "undefined" &&
        this.naturalWidth == 0 ) 
        || this.readyState == 'uninitialized' ) {
        $(this).attr('src', 'missing.jpg');
    }
}); })

Источник: http://www.developria.com/2009/03/jquery-quickie---broken-images.html

  • 1
    Исправлена ошибка, из-за которой onerror не запускался на firefox :) Спасибо.
  • 0
    Работал отлично, спасибо!
10

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

<img src="someimage.jpg" onerror="this.style.display='none';" />
  • 1
    Я нашел это как наиболее надежное для меня решение очень похожей проблемы. Я просто предпочитаю не показывать изображение, а не показывать альтернативу сломанному изображению. Благодарю.
10

Вот быстрый и грязный способ заменить все испорченные изображения, и нет необходимости менять HTML-код;)

пример кода

    $("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"),
            });
        }
  });
8

Это дерьмовая техника, но она в значительной степени гарантирована:

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

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

Я ограничил его до 10 попыток, как если бы он не был загружен, тогда изображение может отсутствовать на сервере, и функция войдет в бесконечный цикл. Я все еще тестирую. Не стесняйтесь настраивать его:)

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);
});
  • 0
    Хорошая идея с попыткой перезагрузить изображения. Это полезно для изображений, которые загружены / автоматически созданы, и сервер, возможно, не был получен / завершен, поскольку страница загружена. Это оригинальное форматирование. Слишком непоследователен и не в моем вкусе, однако ...
5

Вы можете использовать собственную выборку GitHub для этого:

Внешний вид: https://github.com/github/fetch
или для Backend, Node.js версия: https://github.com/bitinn/node-fetch

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

Изменить: этот метод заменит XHR и предположительно уже был в Chrome. Для тех, кто читает это в будущем, вам может не понадобиться упомянутая выше библиотека.

5

Это JavaScript, должен быть совместим с браузером, и обеспечивает без уродливой разметки 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:

4

Чистый JS. Моя задача состояла в том, что если образ "bl-once.png" пуст → вставьте первый из них (который не имеет статуса 404) из списка массивов (в текущем каталоге):

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

Возможно, его нужно улучшить, но:

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

                }
            }
        }

    };

Итак, он будет вставлять правильный "needed.png" в мой src или "no-image.png" из текущего каталога.

  • 0
    Работает ли междоменный?
  • 0
    Я использовал на том же сайте. Это просто идея. Мой реальный код был улучшен ...
4

Вот пример использования объекта HTML5 Image, обернутого JQuery. Вызовите функцию загрузки для URL первичного изображения, и если эта загрузка вызывает ошибку, замените атрибут src изображения URL-адресом резервной копии.

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

Я создал fiddle, чтобы заменить сломанное изображение с помощью события "onerror". Это может вам помочь.

    //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

Я нашел этот пост, смотря на эту другую публикацию SO. Ниже приведена копия ответа, который я дал там.

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

Итак, если вы используете React, вы можете сделать что-то вроде ниже, что было ответом, предоставленным Бен Алпертом команды React здесь

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

Если вы вставили img с помощью innerHTML, например: $("div").innerHTML = <img src="wrong-uri">, вы можете загрузить другое изображение, если оно не выполняется, например:

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

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

Почему требуется javascript: _? Поскольку скрипты, введенные в DOM через теги script в innerHTML, не запускаются во время их ввода, поэтому вы должны быть явным.

4

Используя ответ Prestaul, я добавил несколько проверок, и я предпочитаю использовать способ 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

CoffeeScript вариант:

Я решил исправить проблему с Turbolinks, которая заставляет метод .error() подниматься в Firefox иногда даже несмотря на то, что изображение действительно там.

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

Лучший вызов с использованием

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

Поскольку использование document.ready не требует, чтобы изображения загружались, только HTML. Таким образом, нет необходимости в отсроченном вызове.

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

ссылка

3

Я решил проблему с этими двумя простыми функциями:

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

Я не уверен, есть ли лучший способ, но я могу подумать о взломе, чтобы получить его - вы могли бы отправить Ajax на URL-адрес img и проанализировать ответ, чтобы увидеть, действительно ли изображение вернулось. Если он вернется как 404 или что-то еще, замените img. Хотя я ожидаю, что это будет довольно медленно.

2

Я думаю, что у меня более элегантный способ делегирования событий и захвата событий на window error, даже если резервное изображение не загружается.

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

Точка:

  • Поместите код в head и выполните его как первый встроенный script. Таким образом, он будет выслушивать ошибки после script.

  • Используйте захват событий, чтобы поймать ошибки, особенно для тех событий, которые не пузырятся.

  • Используйте делегирование событий, которое позволяет избежать привязки событий к каждому изображению.

  • Дайте элементу ошибки img атрибут после предоставления им backup.png, чтобы избежать исчезновения backup.png и последующего бесконечного цикла, как показано ниже:

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

2

Если изображение не может быть загружено (например, поскольку оно отсутствует в указанном URL-адресе), URL-адрес изображения будет изменен по умолчанию,

Подробнее о .error()

  $('img'). on ('error', function (e) {
 $(this).attr('src', 'broken.png');
});Код>
2

Это меня расстраивало годами. Мое исправление CSS устанавливает фоновое изображение на img. Когда динамическое изображение src не загружается на передний план, на img bg видна заполнитель. Это работает, если ваши изображения имеют размер по умолчанию (например, height, min-height, width и/или min-width).

Вы увидите значок сломанного изображения, но это улучшение. Протестировано до IE9 успешно. iOS Safari и Chrome даже не показывают сломанную иконку.

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

Добавьте немного анимации, чтобы дать время src для загрузки без фонового мерцания. Chrome постепенно исчезает в фоновом режиме, но на рабочем столе Safari нет.

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

Вы можете передать путь к заполнителю и получить в нем все свойства из объекта неудавшегося изображения через $*:

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

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

1

Иногда использование события error не представляется возможным, например. потому что вы пытаетесь сделать что-то на уже загруженной странице, например, когда вы запускаете код через консоль, букмарклет или script загружается асинхронно. В этом случае проверка того, что img.naturalWidth и img.naturalHeight равна 0, кажется, делает трюк.

Например, здесь приведен фрагмент для перезагрузки всех сломанных изображений с консоли:

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

У меня такая же проблема. Этот код хорошо работает в моем случае.

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

Это решение является простым JavaScript, и оно должно быть совместимым с crossbrowser и поставляет без уродливой разметки 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:

-2

Я нашел, что это работает лучше всего, если какое-либо изображение не загружается в первый раз, оно полностью удаляется из DOM. Выполнение console.clear() обеспечивает чистоту окна консоли, поскольку ошибки 404 нельзя пропустить с помощью блоков try/catch.

$('img').one('error', function(err) {
    // console.log(JSON.stringify(err, null, 4))
    $(this).remove()
    console.clear()
})
  • 2
    На Stack Overflow рекомендуется добавить объяснение того, почему ваше решение должно работать. Для получения дополнительной информации прочитайте, как ответить .
  • 0
    Ответы только на код не приветствуются. Пожалуйста, нажмите на изменить и добавьте несколько слов, обобщающих, как ваш код решает вопрос, или, возможно, объясните, чем ваш ответ отличается от предыдущего ответа / ответов. Из обзора
-5

Я использую приведенный ниже код, который сначала пытается найти текущий аватар пользователя на основе их идентификатора пользователя, который в этом случае равен "123", и если он не находит изображение аватара, код onerror изменяет img src на placeholder изображение.

<img src="avatars/users/123.png" onerror="this.src='/ngTribeBase/src/assets/img/avatars/male.png'" />

Ещё вопросы

Сообщество Overcoder
Наверх
Меню