jQuery / JavaScript для замены сломанных изображений

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

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


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

30 ответов


обработки 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


программа error обработчик:

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

error() осуждается в 1.8 или выше.


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

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

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

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

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


вот вам самостоятельное решение:

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

Я считаю, что это то, что вы после: С помощью jQuery.Поджатие

вот пример кода из демо, вы указываете загрузку и не нашли изображения, и все готово:

$('#images img').preload({
    placeholder:'placeholder.jpg',
    notFound:'notfound.jpg'
});

$(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


это дерьмовый метод, но это в значительной степени гарантировано:

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

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

<img src="someimage.jpg" onerror="this.style.display='none';" />

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

пример codepen

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

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

Я ограничил его 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);
});

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

интерфейс:https://github.com/github/fetch
или для бэкэнда, узла.версия js:https://github.com/bitinn/node-fetch

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

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


это 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:


лучше позвонить с помощью

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

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


CoffeeScript вариант:

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

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

С помощью 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;
}

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

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

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

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


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

Я знаю, что это старый поток, но 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} />;
    );
}

Я создал скрипка для замены сломанного изображения с помощью события" 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\(['"](.+)['"]\)/, '');
      $('<img>', {
        src: currentUrl
      }).on("error", function(e) {
        $this = $(this);
        $this.css({
          "background-image": defaultUrl
        })
        e.target.remove()
      }.bind(this))
    })

вот пример использования объекта изображения HTML5, обернутого JQuery. Вызовите функцию load для основного 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>

чистый JS. Моя задача была: если изображение ' BL-один раз.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();
                    }

                }
            }
        }

    };

Так, это вставить правильно необходимо.png "для моего src или" no-image.ПНГ с текущего каталога.


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


Я решил свою проблему с помощью этих двух простых функций:

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

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

ссылка


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


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

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

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

добавить немного анимации, чтобы дать src время загрузки без фонового мерцания. Chrome плавно исчезает в фоновом режиме, но desktop 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; }
}

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

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

$('img').on('error', function (e) {
  $(this).attr('src', 'broken.png');
});

Я думаю, что у меня есть более элегантный способ с делегированием событий и захватом событий на window ' s 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">

суть :

  1. вставить код в тег head и выполняется как первый встроенный скрипт. Таким образом, он будет слушать ошибки, возникающие после сценария.

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

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

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

ошибка img - >резервное копирование.png - >ошибка - >резервное копирование.ПНГ->ошибка->,,,,,


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

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

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

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

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

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

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