壊れた画像を置き換えるjQuery / JavaScript


547

たくさんの画像を含むウェブページがあります。画像が利用できない場合があるため、壊れた画像がクライアントのブラウザに表示されます。

jQueryを使用して画像のセットを取得し、壊れた画像にフィルター処理して、srcを置き換えるにはどうすればよいですか?


--jQueryでこれを行う方が簡単だと思いましたが、純粋なJavaScriptソリューション、つまりPrestaulが提供するものを使用する方がはるかに簡単であることがわかりました。

回答:


760

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


132
おそらく、srcを設定する前に onerrorをクリアしたいと思うでしょう。そうでない場合、noimage.gifも欠落していると、「スタックオーバーフロー」が発生する可能性があります。
pcorcoran 2008

45
JavaScriptイベントのインライン属性から離れることを考え、希望しました...
redsquare 2009

24
redsquare ...それらは、制御下に置くことについて賢明である場合に完全に理解可能であり、実際に何が起こるかをマークアップに反映させたい場合にも役立ちます。
ニコール

2
良い点NickC、何が起こっているのかを示すマークアップについて、私はそれを見るとうんざりしています:P
SSH This

38
@redsquare、私は完全に同意しますが、これはユニークなケースです。インラインは、リスナーが接続される前にイベントがトリガーされないという絶対的な確信を持ってリスナーを接続できる唯一の場所です。ドキュメントの最後でそれを行うか、DOMがロードされるのを待つと、一部の画像でエラーイベントを見逃す可能性があります。イベントが発生した後でエラーハンドラーをアタッチしても意味がありません。
Prestaul

201

私は組み込みのerrorハンドラーを使用します:

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

編集:このerror()メソッドはjquery 1.8以降では非推奨です。代わりに、代わりに使用する必要があります.on("error")

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

112
この手法を使用する場合は、「one」メソッドを使用して、イベントをアンバインドする必要を回避できます:$( 'img')。one( 'error'、function(){this.src = 'broken.gif';}) ;
Prestaul

7
+1しかし、バインドを解除する必要がありますか?バインドを解除しないと、動的な画像(ホバー時に変化する画像など)で美しく機能します。
Aximili

15
バインドを解除しないと、broken.gif srcリファレンスが何らかの理由でロードに失敗する場合、ブラウザで問題が発生する可能性があると思います。
トラビス

4
@travis、いつこの電話をかけますか?このメソッドを使用する方法はありますか?エラーイベントが発生する前にハンドラーがアタッチされていることを確認してください。
Prestaul

5
ここでは、イベントハンドラの前にエラー火災が装着されている場合の例は次のとおりです。jsfiddle.net/zmpGz/1私はこのハンドラをアタッチするフェイルセーフな方法がある場合は純粋に好奇心が強い...
Prestaul

120

私のような誰かがerrorイベントをダイナミックHTML imgタグに添付しようとする場合、それを指摘したいのですが、問題があります。

どうやら、imgエラーイベント標準が言っていることとは逆に、ほとんどのブラウザーでバブルません

したがって、次のようなものは機能しません

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

これが他の誰かに役立つことを願っています。このスレッドでこれを見たならいいのに。しかし、私はしませんでした。だから、私はそれを追加しています


うまくいきませんでした。死んだ画像を動的にロードしてdomに追加しましたが、「エラー」イベントは発生しません。
vsync

59

これがスタンドアロンソリューションです。

$(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)))に変更しました
Sugendran

3
これは、ページの読み込み後に壊れた画像を検出できるためです。私はこれが必要でした。
北米の2013

@Sugendran $.browserは非推奨になり、削除されました。代わりに機能検出を使用してください(この場合はさらに複雑になります)。
lee penkman 14

3
スタンドアロンですが、jQueryが必要ですか?
チャーリー

これはうまくいきますが、画像のsrcがを返す204 No Contentと、壊れた画像になります。
Carson Reinke 2016年

35

私はこれがあなたが望んでいることだと信じています:jQuery.Preload

デモのサンプルコードは次のとおりです。ロードする画像と見つからない画像を指定すると、準備は完了です。

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

1
jQuery.Preloadは、サンプルコードを使用するために必要なプラグインです。
ダン卿

17
はい...これは最初の行の回答にリンクされています。
Nick Craver

ニックさん、ありがとうございます。これは、Firefoxの8年以上前の問題で、壊れた画像の代わりに画像が表示されないという優れた解決策のようです。さらに、ささいなことをブランド化することができます...ありがとう。
クレウィス2014


19

OPはSRCを置き換えるために探していましたが、私はこの質問を打つ多くの人々は唯一、その場合には壊れた画像、非表示にしたいことが確信しているこの単純な解決策は、私のために素晴らしい仕事を。

インラインJavaScriptの使用:

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

外部JavaScriptの使用:

var images = document.querySelectorAll('img');

for (var i = 0; i < images.length; i++) {
  images[i].onerror = function() {
    this.style.display='none';
  }
}
<img src='img.jpg' />

最新の外部JavaScriptの使用:

document.querySelectorAll('img').forEach((img) => {
  img.onerror = function() {
    this.style.display = 'none';
  }
});
<img src='img.jpg' />

NoteList.forEachおよびarrow関数のブラウザサポートを参照してください。


1
これは、私にとって非常に類似した問題に対する最も信頼できる解決策であることがわかりました。壊れた画像の代替案を表示するよりも、画像を表示しない方がいいです。ありがとう。
pc_ 2018

コンテンツセキュリティポリシーがインラインスクリプトを許可していない場合、これは明らかに機能しません。
isherwood

@isherwood良い点。外部JSファイルを介して機能するソリューションを追加しました。
Nathan Arthur

11

壊れた画像をすべて置き換える簡単な方法を以下に示します。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"),
            });
        }
  });

9

自分のニーズに合うスクリプトが見つからなかったので、壊れた画像をチェックし、修正されるまで4秒ごとに再読み込みを試みる再帰関数を作成しました。

ロードされなかったかのように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);
});

画像をリロードしてみてください。これは、アップロード/自動生成された画像に役立ち、ページが読み込まれるときにサーバーが取得/完了していない可能性があります。それはいくつかの元のフォーマットです。少し一貫性がなく、私の好みではありませんが...
Joakim

8

これはくだらないテクニックですが、ほぼ保証されています。

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

6

これにはGitHub独自のフェッチを使用できます。

フロントエンド:https : //github.com/github/fetch
またはバックエンドの場合、Node.jsバージョン:https : //github.com/bitinn/node-fetch

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

編集:このメソッドはXHRに取って代わるものであり、おそらくChromeにすでに含まれています。将来これを読む人には、前述のライブラリを含める必要はないかもしれません。


6

これは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] );
}

コーデックペン:


以下のためにupvotewhile (i--)
S3C

4

より良い通話

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

を使用document.readyしても画像が読み込まれる必要はなく、HTMLのみが読み込まれます。したがって、遅延コールの必要はありません。


4

CoffeeScriptバリアント:

画像が実際に存在するにもかかわらず、Firefoxで.error()メソッドが発生することがあるTurbolinksの問題を修正するために作成しました。

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

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

のようにimgwith を挿入した場合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に挿入されたスクリプトは、挿入innerHTML時に実行されないため、明示的にする必要があります。


4

私はこの他のSO投稿を見ている間にこの投稿を見つけました。以下は私がそこで与えた答えのコピーです。

私はこれが古いスレッドであることを知っていますが、Reactが人気になり、おそらくReactを使用している誰かが同じ問題の答えを探してここに来るでしょう。

したがって、Reactを使用している場合は、以下のようなことができます。これは、ReactチームのBen Alpertによって提供された回答の原文です。

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

「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

以下は、JQueryによってラップされたHTML5 Imageオブジェクトを使用した例です。プライマリイメージ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

純粋な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」に挿入します。


同じサイトで使用しました。これは単なる考えです。私の実際のコードが...改善されました
ДмитрийДорогонов

3

より良い方法があるかどうかはわかりませんが、それを取得するためのハックを考えることができます。Ajaxがimg URLに投稿し、応答を解析して画像が実際に戻ったかどうかを確認できます。404または何かとして戻ってきた場合は、imgを交換してください。これはかなり遅いと思いますが。


3

私はこれら2つの単純な関数で問題を解決しました:

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

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

私はイベントの代表団とイベントが上のキャプチャで、よりエレガントな方法があると思うwindowerrorバックアップイメージがロードに失敗した場合でも。

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 error-> backup.png-> error-> backup.png-> error-> ,,,,,


これは断然最高の答えです。私が提案する唯一のことはlet isImgErrorHandled = target.src === 'backup.png';、それが少し簡単になるので使用することです。
砂防

@ Sabo、srcパスが割り当てたパスと異なる場合があるため、少し問題があります。たとえばtarget.src='backup.png'、ただし次回console.log(target.src)はそうでない可能性がありますbackup.png
xianshenglu

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/


2

これは何年もの間私を苛立たせてきました。CSSの修正により、背景画像がに設定されますimg。ダイナミック画像srcがフォアグラウンドに読み込まれない場合、プレースホルダーがimgのbgに表示されます。あなたのイメージは、デフォルトのサイズを持っている場合、これは動作します(たとえばheightmin-heightwidthおよび/または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

画像がロードできない場合(たとえば、提供されたURLに画像が存在しないため)、画像のURLはデフォルトに変更されます。

.error()についての詳細

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


1

同じ問題が発生しました。このコードは私の場合にうまく機能します。

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

1

errorたとえば、コンソール、ブックマークレット、または非同期に読み込まれたスクリプトを介してコードを実行している場合など、既に読み込まれているページで何かを実行しようとしているため、イベントを使用できない場合があります。その場合、それを確認しimg.naturalWidthimg.naturalHeight is 0をうまくいくようです。

たとえば、次のスニペットは、壊れた画像をすべてコンソールから再読み込みします。

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

0

これが最も効果的であることがわかりました。最初に画像を読み込めない場合は、DOMから完全に削除されます。実行console.clear()すると、try / catchブロックで404エラーを省略できないため、コンソールウィンドウがクリーンに保たれます。

$('img').one('error', function(err) {
    // console.log(JSON.stringify(err, null, 4))
    $(this).remove()
    console.clear()
})
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.