JavaScriptで画像の読み込みに失敗したことを検出する


103

画像パスが実際の画像につながるかどうかを判断する方法はありますか。つまり、JavaScriptで画像の読み込みに失敗した場合にそれを検出します。

Webアプリの場合は、xmlファイルを解析して、画像パスのリストからHTML画像を動的に作成しています。一部の画像パスがサーバーに存在しなくなった可能性があるため、ロードに失敗した画像を検出し、そのHTML img要素を削除することで、正常に失敗したいと思います。

注:JQueryソリューションは使用できません(上司はJQueryを使用したくないので、はい、始めません)。画像が読み込まれたときにJQueryで検出する方法は知っていますが、失敗したかどうかはわかりません。

img要素を作成するコードですが、imgパスが画像の読み込みに失敗したかどうかをどのように検出できますか?

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

これはあなたを助けるかもしれません:stackoverflow.com/questions/1977871/…(それはjQueryですが、それでも正しい道にあなたを導くかもしれません)
Ben Lee


2
面白い@ ajax333221まさにこの質問があなたのリンクの結果の最初にあります:)
SSHこの

新しいBossを見つけるためのJQueryセレクターを記述します。インターネットは大きな場所です。
JJS

回答:


113

次のコードを試すことができます。ただし、ブラウザの互換性を保証することはできないので、テストする必要があります。

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 2014年

4
これは、イメージの取得元のサーバーによっては、webKit(Epiphany、Safari、...)では機能しません。たとえば、imgurが存在する画像や404ステータスを送信しないことがあり、この場合はエラーイベントがトリガーされません。

この問題は、「その画像が見つかりませんでした」というメッセージです。応答コードは、500や403などです。あなたはそれが404だったことを知りません。実際には、それが404である可能性は非常に低いです。
PHPグル

1
直接割り当ての代わりにイベントハンドラーを追加する必要があります
cdalxndr

50

答えはいいですが、問題が1つあります。onloadまたはonerror直接割り当てると、以前に割り当てられたコールバックが置き換えられる可能性があります。MDNで言うように、「指定されたリスナーを、呼び出されたEventTargetに登録する」という素晴らしいメソッドがあるのはそのためです。同じイベントに必要な数のリスナーを登録できます。

答えを少し書き直してみましょう。

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

外部リソースの読み込みプロセスは非同期であるため、次のようなPromiseを備えた最新の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 2017

1
@JohnWeisz Arrow関数は匿名であるため、デバッグは難しく、慎重に使用してください。
emil.c 2017年

10
@GifCo私はあなたとそのような議論を続けることを快く思いません。私はあなたの言葉に気分を害します。私の答えが正しくないか不完全であると思われる場合は、変更を提案し、理由を説明してください。何かが悪い習慣だと思うなら、あなた自身の答えで良い実践を提案してください。
emil.c 2017

1
なぜここでアロー関数についての議論があるのですか?話題外です。古いブラウザ(たとえばInternet Explorer)が矢印機能をサポートしていないので、答えは特に問題ありません。
PHPグル

29

この:

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

1
これはイメージフェイルオーバーテクニックとして使用できる便利な属性ですが、より詳細な応答は読者が理解するのに役立ちます。
18

1
とても短くてとても便利です!単に非表示にするため:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM

2
@sorakのコメントは嫌悪感で私を笑わせました。これが正解です。
user3751385

@ J0ANMM画像を非表示にするもう1つの方法は、空のalt属性を追加することです。<img alt = "" src = "yourpicture.png">
Rick Glimmer

優れた!画像にフェールオーバーする代わりに、このテキストを印刷します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 + img用CSS

jQueryでこれは私のために働いています:

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

次のCSS3プロパティを使用すると、サイズに関係なく、この画像をWebサイトのどこにでも使用できます。

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

ヒント1:少なくとも800 x 800ピクセルの正方形の画像を使用します。

ヒント2:人物のポートレートで使用する場合は、object-position: 20% 50%;

background-img専用のCSS

不足している背景画像については、各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。それはあなたが必要な正確に何だかどうかは知りませんが、それはあなたがハンドラが含まれ使用する様々な技術使用しonloadonerroronabortおよび一般的なタイムアウトを。

画像の読み込みは非同期であるため、この関数を画像で呼び出してから、後でコールバックを呼び出して結果を返します。


-19

以下のように:

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

if (!img.complete) {

//has picture
}
else //not{ 

}

3
いいえ。これは、一部のブラウザでは、画像がキャッシュされているかどうかの手がかりになるかもしれませんが、ロードコールバックがないと、ブラウザにその画像のHTTPリクエストを開始する機会を与えるのに一瞬も待ちません。
ChaseMoskal 2013年

これは単に何かを言うためのものです!
Hitmands

4
画像の読み込みは非同期です。
emil.c 2016

@ emil.cなんらかの理由で、常にそうとは限りません。ChaseMoskal(SOは私に通知させません...)はそれを正しく持っています-これは、JSの実行が続く前にイメージのロードが完了した場合にのみ機能します。これは、キャッシュされるたびに発生するようです。
トリスタン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.