Phát hiện khi hình ảnh không tải được trong Javascript


104

Có cách nào để xác định xem đường dẫn hình ảnh có dẫn đến hình ảnh thực hay không, tức là phát hiện khi hình ảnh không tải được trong Javascript.

Đối với một ứng dụng web, tôi đang phân tích cú pháp tệp xml và tạo động các hình ảnh HTML từ danh sách các đường dẫn hình ảnh. Một số đường dẫn hình ảnh có thể không còn tồn tại trên máy chủ, vì vậy tôi muốn xử lý sự cố bằng cách phát hiện hình ảnh nào không tải được và xóa phần tử HTML img đó.

Lưu ý rằng các giải pháp JQuery sẽ không thể được sử dụng (ông chủ không muốn sử dụng JQuery, vâng, tôi biết không giúp tôi bắt đầu). Tôi biết một cách trong JQuery để phát hiện khi nào một hình ảnh được tải, nhưng không biết liệu nó có bị lỗi hay không.

Mã của tôi để tạo các phần tử img nhưng làm cách nào tôi có thể phát hiện nếu đường dẫn img dẫn đến không tải được hình ảnh?

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

Điều này có thể giúp bạn: stackoverflow.com/questions/1977871/... (nó jQuery, nhưng nó vẫn có thể dẫn bạn trên con đường bên phải)
Ben Lee

hãy thử một trong những google.com/…
ajax333221

2
Funny @ ajax333221 câu hỏi này nằm đầu tiên trong kết quả liên kết của bạn :)
SSH

viết bộ chọn JQuery để tìm Boss mới ... internet là một nơi rộng lớn.
JJS

Câu trả lời:


115

Bạn có thể thử mã sau. Tuy nhiên, tôi không thể đảm bảo về khả năng tương thích của trình duyệt, vì vậy bạn sẽ phải kiểm tra điều đó.

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

Và tôi thông cảm cho ông chủ chống lại jQuery!


2
Bất kỳ ý tưởng nếu có một cách để biết nếu nó gặp phải một chuyển hướng?
quickshiftin

4
Điều này không hoạt động trên webKit (Epiphany, Safari, ...) tùy thuộc vào máy chủ mà bạn đang nhận hình ảnh. Ví dụ: đôi khi imgur không gửi hình ảnh tồn tại cũng như trạng thái 404 và sự kiện lỗi không được kích hoạt trong trường hợp này.

Vấn đề với điều này là thông báo của bạn, "Hình ảnh đó không được tìm thấy." Mã phản hồi có thể là 500 hoặc 403 hoặc một cái gì đó khác. Bạn không biết rằng đó là 404. Trên thực tế, không có nhiều khả năng đó là 404 vì bạn có thể sẽ không thử tải một hình ảnh không có ở đó.
PHP Guru

1
nên thêm trình xử lý sự kiện thay vì chỉ định trực tiếp
cdalxndr Ngày

50

Câu trả lời rất hay, nhưng nó giới thiệu một vấn đề. Bất cứ khi nào bạn chỉ định onloadhoặc onerrortrực tiếp, nó có thể thay thế lệnh gọi lại đã được chỉ định trước đó. Đó là lý do tại sao có một phương pháp hay là "đăng ký trình lắng nghe được chỉ định trên EventTarget mà nó được gọi" như họ nói trên MDN . Bạn có thể đăng ký bao nhiêu người nghe tùy ý trong cùng một sự kiện.

Hãy để tôi viết lại câu trả lời một chút.

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

Bởi vì quá trình tải tài nguyên bên ngoài là không đồng bộ, sẽ tốt hơn nếu sử dụng JavaScript hiện đại với các hứa hẹn, chẳng hạn như sau.

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
có thể tôi đang thiếu thứ gì đó, nhưng làm cách nào để bài tập (tester.onload = ..) có thể thay thế lệnh gọi lại, nếu "tester" vừa được tạo? ngay cả khi một số phần bị che khuất của mã thêm một sự kiện vào mỗi hình ảnh được tạo, không rõ ràng là chúng tôi muốn giữ những sự kiện đó với mục đích phát hiện xem một hình ảnh có tồn tại hay không.
jvilhena

1
Bạn hoàn toàn chính xác. Trong trường hợp cụ thể này, nó có thể không thành vấn đề vì rất có thể nó sẽ không được thay thế. Tuy nhiên, nói chung, việc thêm một trình nghe sự kiện sẽ tốt hơn là chỉ định một phương pháp trực tiếp.
emil.c

1
@JohnWeisz Các hàm Arrow là ẩn danh, do đó khó gỡ lỗi hơn, hãy sử dụng chúng cẩn thận.
emil.c

10
@GifCo Tôi không cảm thấy thoải mái khi tiếp tục thảo luận như vậy với bạn. Tôi cảm thấy bị xúc phạm bởi ngôn ngữ của bạn. Nếu bạn tin rằng câu trả lời của tôi không chính xác hoặc không đầy đủ, hãy đề xuất thay đổi và giải thích lý do của bạn. Nếu bạn nghĩ điều gì đó là thực hành XẤU, hãy đề xuất một phương pháp thực hành tốt với câu trả lời của riêng bạn.
emil.c

1
Tại sao có một cuộc thảo luận về các chức năng mũi tên ở đây? Nó lạc đề. Câu trả lời là tốt, đặc biệt là vì các trình duyệt cũ không hỗ trợ các chức năng mũi tên (ví dụ như Internet Explorer).
PHP Guru

29

Điều này:

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

1
Mặc dù đây là một thuộc tính hữu ích có thể được sử dụng như một kỹ thuật chuyển đổi dự phòng hình ảnh, nhưng một phản hồi dài dòng hơn sẽ hữu ích cho người đọc hiểu nó.
sorak

1
Thật ngắn gọn và hữu ích! Để chỉ ẩn nó:<img src="your/path/that/might/fail.png" onerror="$(this).hide();"/>
J0ANMM

2
Bình luận của @ sorak khiến tôi bật cười kinh tởm. Đây là câu trả lời chính xác.
user3751385,

@ J0ANMM Một cách khác để ẩn hình ảnh là thêm thuộc tính alt trống: <img alt = "" src = "yourpicture.png">
Rick Glimmer,

Thông minh! Thay vì không xem được hình ảnh, tôi in văn bản này onerror = "this.alt = 'Hình ảnh không hợp lệ, hãy sử dụng liên kết ^'"
mồ hôi

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 cho img

Với jQuery, điều này làm việc cho tôi:

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

Và tôi có thể sử dụng ảnh này ở mọi nơi trên trang web của mình bất kể kích thước của nó với thuộc tính CSS3 sau:

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

MẸO 1: sử dụng hình ảnh vuông có kích thước tối thiểu 800 x 800 pixel.

MẸO 2: để sử dụng với chân dung người , hãy sử dụngobject-position: 20% 50%;

CSS chỉ dành cho background-img

Đối với những hình nền bị thiếu, tôi cũng đã thêm những điều sau vào mỗi background-imagekhai báo:

background-image: url('path-to-image.png'), url('no-img.png');

LƯU Ý: không hoạt động đối với hình ảnh trong suốt.

Phía máy chủ Apache

Một giải pháp khác là phát hiện hình ảnh bị thiếu với Apache trước đó để gửi đến trình duyệt và thay thế nó bằng nội dung no-img.png mặc định.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} /images/.*\.(gif|jpg|jpeg|png)$
RewriteRule .* /images/no-img.png [L,R=307]

3

Đây là một chức năng tôi đã viết cho một câu trả lời khác: Xác minh Url hình ảnh Javascript . Tôi không biết nếu đó là chính xác những gì bạn cần, nhưng nó sử dụng các kỹ thuật khác nhau mà bạn sẽ sử dụng trong đó bao gồm xử lý cho onload, onerror, onabortvà một thời gian chờ chung.

Bởi vì quá trình tải hình ảnh không đồng bộ, bạn gọi hàm này với hình ảnh của mình và sau đó nó sẽ gọi lại hàm của bạn vào một thời gian sau với kết quả.


-19

giống như bên dưới:

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

if (!img.complete) {

//has picture
}
else //not{ 

}

3
Không. Điều này có thể cho bạn biết liệu hình ảnh có được lưu vào bộ nhớ đệm hay không, trong một số trình duyệt - nhưng nếu không có lệnh gọi lại tải, bạn sẽ không đợi dù chỉ một chút thời gian để trình duyệt có cơ hội bắt đầu một yêu cầu HTTP cho hình ảnh đó.
ChaseMoskal

điều này chỉ để nói điều gì đó!
Hitmands

4
Tải hình ảnh không đồng bộ.
emil.c

@ emil.c không phải lúc nào cũng vậy, vì một số lý do. ChaseMoskal (người mà SO sẽ không cho tôi thông báo ...) có quyền - điều này chỉ hoạt động nếu hình ảnh tải xong trước khi tiếp tục thực thi JS, điều này dường như xảy ra bất cứ khi nào nó được lưu vào bộ nhớ cache.
tristan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.