Làm cách nào để xác định xem hình ảnh đã được tải bằng cách sử dụng Javascript / jQuery?


85

Tôi đang viết một số Javascript để thay đổi kích thước hình ảnh lớn cho vừa với cửa sổ trình duyệt của người dùng. (Rất tiếc, tôi không kiểm soát kích thước của hình ảnh nguồn.)

Vì vậy, một cái gì đó như thế này sẽ có trong HTML:

<img id="photo"
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Có cách nào để tôi xác định xem srchình ảnh trong imgthẻ đã được tải xuống chưa?

Tôi cần điều này vì tôi đang gặp sự cố nếu $(document).ready()được thực thi trước khi trình duyệt tải hình ảnh. $("#photo").width()$("#photo").height()sẽ trả về kích thước của trình giữ chỗ (văn bản thay thế). Trong trường hợp của tôi, đây là một cái gì đó giống như 134 x 20.

Hiện tại, tôi chỉ đang kiểm tra xem chiều cao của bức ảnh có nhỏ hơn 150 hay không và giả sử rằng nếu có thì đó chỉ là văn bản thay thế. Nhưng đây là một vụ hack và nó sẽ bị hỏng nếu ảnh cao dưới 150 pixel (không có khả năng xảy ra trong trường hợp cụ thể của tôi) hoặc nếu văn bản thay thế cao hơn 150 pixel (có thể xảy ra trên một cửa sổ trình duyệt nhỏ) .


Chỉnh sửa: Đối với bất kỳ ai muốn xem mã:

$(function()
{
  var REAL_WIDTH = $("#photo").width();
  var REAL_HEIGHT = $("#photo").height();

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()
  {
    if(REAL_HEIGHT < 150)
    {
      REAL_WIDTH = $("#photo").width();
      REAL_HEIGHT = $("#photo").height();
      if(REAL_HEIGHT < 150)
      {
        //image not loaded.. try again in a quarter-second
        setTimeout(adjust_photo_size, 250);
        return;
      }
    }

    var new_width = . . . ;
    var new_height = . . . ;

    $("#photo").width(Math.round(new_width));
    $("#photo").height(Math.round(new_height));
  }

});

Cập nhật : Cảm ơn vì những đề xuất. Có nguy cơ sự kiện không được kích hoạt nếu tôi đặt lệnh gọi lại cho $("#photo").loadsự kiện, vì vậy tôi đã xác định sự kiện onLoad trực tiếp trên thẻ hình ảnh. Đối với bản ghi, đây là mã tôi đã kết thúc với:

<img id="photo"
     onload="photoLoaded();"
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Sau đó trong Javascript:

//This must be outside $() because it may get called first
var isPhotoLoaded = false;
function photoLoaded()
{
  isPhotoLoaded = true;
}

$(function()
{
  //Hides scrollbars, so we can resize properly.  Set with JS instead of
  //  CSS so that page doesn't break with JS disabled.
  $("body").css("overflow", "hidden");

  var REAL_WIDTH = -1;
  var REAL_HEIGHT = -1;

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()
  {
    if(!isPhotoLoaded)
    {
      //image not loaded.. try again in a quarter-second
      setTimeout(adjust_photo_size, 250);
      return;
    }
    else if(REAL_WIDTH < 0)
    {
      //first time in this function since photo loaded
      REAL_WIDTH = $("#photo").width();
      REAL_HEIGHT = $("#photo").height();
    }

    var new_width = . . . ;
    var new_height = . . . ;

    $("#photo").width(Math.round(new_width));
    $("#photo").height(Math.round(new_height));
  }

});

1
Điều này quá cũ và bạn đã chấp nhận một câu trả lời, vì vậy tôi sẽ chỉ nhận xét ở đây. Tại sao bạn không thể sử dụng plugin jQuery 'onImagesLoad'? Ngoài ra, jQuery hay không, có gì sai trong việc thiết lập max-widthmax-heighttạo kiểu hình ảnh với Javascript? Sau đó, bạn tránh TẤT CẢ mã bạn cần viết bằng cách đặt chiều rộng / chiều cao tối đa thành kích thước của chiều rộng / chiều cao khung nhìn.

@ jon.wd7: Tôi không quen với plugin đó và có thể nó đã không có từ năm '08. đối với chiều rộng tối đa và chiều cao tối đa, hai điều: 1) chúng không được hỗ trợ trong IE (tôi cũng không chắc về IE 8); 2) nếu chế độ xem thay đổi kích thước (cửa sổ được thay đổi kích thước, v.v.) thì tôi vẫn cần javascript để thay đổi chiều rộng tối đa / chiều cao tối đa (mặc dù tôi có thể không nếu tôi sử dụng "100%" thay vì đo pixel)
Kip

Nó chắc chắn được hỗ trợ trong IE7 và IE8, theo quirksmode.org. Vì vậy, tôi không chắc chắn về vấn đề của bạn. Cá nhân tôi không hỗ trợ IE6 cho những thứ nhỏ như thế này, vì vậy những gì họ sẽ thấy cũng giống như những gì người dùng không bật JS sẽ thấy. Và tất nhiên bạn sẽ cần phải đặt lại max-widthmax-heightthay đổi kích thước. Nhưng đó là một nhiệm vụ khá dễ dàng, .resize()thực tế là sử dụng một lớp lót .

3
Các hoàn tài sản cho con đường bắt buộc biết liệu hình ảnh đã được tải.
BorisOkunskiy 23/09/13

1
@Adrien, Mozilla hiện đã hiển thị hoàn chỉnh khi được tất cả các trình duyệt chính hỗ trợ, ngoại trừ Andoid (không xác định).
Oliver Bock

Câu trả lời:


33

Thêm người nghe sự kiện hoặc để hình ảnh tự thông báo khi tải lên. Sau đó, tính ra các kích thước từ đó.

<img id="photo"
     onload='loaded(this.id)'
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Theo thông số kỹ thuật, onload chỉ là một sự kiện cho phần thân và phần tử bộ khung; điều đó nói rằng, tôi nghĩ rằng điều này hoạt động trong IE, nhưng tôi không biết rằng nó hoạt động trong bất kỳ trình duyệt nào khác hoặc đó là điều bạn có thể cho là ... Tôi chỉ mới xem xét điều này vài tuần trước ...
Jason Bunting

Tôi đã thử nghiệm nó trong IE6, IE7, FF3, Opera9, Safair (Windows Beta) và Chrome (Windows Beta).
Kip

9
Hành vi và nội dung lộn xộn không được khuyến khích. Sự kiện nên được áp dụng bằng Javascript, không phải bằng HTML.
dionyziz 14/12/12

10
Nhận xét của anh ấy LÀ có liên quan vì chúng tôi không bị mắc kẹt vào năm 2008. Mọi người vẫn đọc điều này, và thậm chí nó không bị coi là thực hành xấu vào năm 08, bạn không muốn mọi người nghĩ rằng thực hành tốt của nó bây giờ.
Spoeken

3
document.querySelector ("img"). addEventListener ("load", function () {alert ('onload!');});
Frank Schwieterman

14

Sử dụng kho dữ liệu jquery, bạn có thể xác định trạng thái 'đã tải'.

<img id="myimage" onload="$(this).data('loaded', 'loaded');" src="lolcats.jpg" />

Sau đó, ở những nơi khác bạn có thể làm:

if ($('#myimage').data('loaded')) {
    // loaded, so do stuff
}

2
Sử dụng jQuery(this)thay vì $(this)để tương thích tốt hơn với các thư viện khác (jquery không sở hữu $), đặc biệt khi bạn có JavaScript trong html.
John Magnolia

11

Câu trả lời đúng là sử dụng event.special.load

Có thể sự kiện tải sẽ không được kích hoạt nếu hình ảnh được tải từ bộ nhớ cache của trình duyệt. Để giải thích khả năng này, chúng tôi có thể sử dụng sự kiện tải đặc biệt sẽ kích hoạt ngay lập tức nếu hình ảnh đã sẵn sàng. event.special.load hiện có sẵn dưới dạng một plugin.

Theo tài liệu trên .load ()


2
Tôi sẽ thêm một câu trả lời với một gợi ý như thế này, rất vui vì tôi đã xem câu trả lời này trước khi viết mã. Về cơ bản, trình xử lý của bạn trước tiên cần kiểm tra xem hình ảnh có được tải hay không trước khi thiết lập trình xử lý. Nếu nó đã được tải, hãy kích hoạt cuộc gọi lại ngay lập tức. Đó là những gì $.readyhiện. Tôi đã định đề nghị chỉ kiểm tra chiều rộng, nhưng điều đó có vấn đề của nó, tôi thực sự thích giải pháp đó.
Juan Mendes

5

Bạn muốn làm những gì Allain đã nói, tuy nhiên hãy lưu ý rằng đôi khi hình ảnh tải trước khi dom sẵn sàng, có nghĩa là trình xử lý tải của bạn sẽ không kích hoạt. Cách tốt nhất là làm như Allain nói, nhưng đặt src của hình ảnh bằng javascript sau khi đính kèm trình xử lý tải. Bằng cách này bạn có thể đảm bảo rằng nó cháy.

Về khả năng truy cập, liệu trang web của bạn có còn hoạt động cho những người không có javascript không? Bạn có thể muốn cung cấp cho thẻ img đúng src, đính kèm trình xử lý sẵn sàng dom để chạy js của bạn: xóa hình ảnh src (cung cấp cho nó một giá trị cố định với và chiều cao bằng css để ngăn trang nhấp nháy), sau đó đặt trình xử lý tải img của bạn, sau đó đặt lại src thành tệp chính xác. Bằng cách này bạn bao gồm tất cả các cơ sở :)


Trang web vẫn hoạt động cho những người không có Javascript, họ chỉ cần cuộn để xem tất cả hình ảnh.
Kip

4

Theo một trong những nhận xét gần đây cho câu hỏi ban đầu của bạn

$(function() {

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()  {
    if (!$("#photo").get(0).complete) {
       $("#photo").load(function() {
          adjust_photo_size();
       });
    } else {
      ... 
    }
});

Cảnh báo Câu trả lời này có thể gây ra một vòng lặp nghiêm trọng trong ie8 trở xuống, vì img.complete không phải lúc nào cũng được trình duyệt đặt đúng cách. Nếu bạn phải hỗ trợ ie8, hãy sử dụng cờ để ghi nhớ hình ảnh được tải.


Giữ lấy nó. Câu trả lời này có thể gây ra một vòng lặp nghiêm trọng trong ie8 trở xuống, vì img.complete không phải lúc nào cũng được trình duyệt đặt đúng cách. Nếu bạn phải hỗ trợ ie8, hãy sử dụng cờ để ghi nhớ hình ảnh được tải.
commonpike

2

Hãy thử một cái gì đó như:

$("#photo").load(function() {
    alert("Hello from Image");
});

6
Cảm ơn. Tuy nhiên, có khả năng hình ảnh đã được tải trước khi điều này xảy ra, trong trường hợp đó, sự kiện tải sẽ không được kích hoạt.
Kip

Làm thế nào về một thẻ script thiết lập sự kiện này ngay sau thẻ hình ảnh? Lý do để sử dụng ready là để đảm bảo toàn bộ tài liệu được tải, điều này là không cần thiết trong trường hợp này, phải không?
Jason Goemaat

2

Có một plugin jQuery được gọi là "imagesLoaded" cung cấp phương pháp tương thích với nhiều trình duyệt để kiểm tra xem (các) hình ảnh của phần tử đã được tải chưa.

Trang web: https://github.com/desandro/imagesloaded/

Cách sử dụng cho một vùng chứa có nhiều hình ảnh bên trong:

$('container').imagesLoaded(function(){
 console.log("I loaded!");
})

Plugin rất tuyệt:

  1. hoạt động để kiểm tra một vùng chứa có nhiều hình ảnh bên trong
  2. hoạt động để kiểm tra một img để xem nó đã được tải chưa

có vẻ hơi nặng 5KB được giảm thiểu chỉ để kiểm tra img đã tải. Nên có một phương pháp nhẹ hơn dễ dàng hơn ...
cdalxndr

1

Bất kỳ ý kiến ​​về điều này?

...

doShow = function(){
  if($('#img_id').attr('complete')){
    alert('Image is loaded!');
  } else {
    window.setTimeout('doShow()',100);
  }
};

$('#img_id').attr('src','image.jpg');

doShow();

...

Có vẻ như hoạt động ở khắp mọi nơi ...


thực tế không tốt để sử dụngsetTimeout
cdalxndr

1

Tôi vừa tạo một hàm jQuery để tải một hình ảnh bằng jQuerys Deferred Object , điều này làm cho nó rất dễ phản ứng với sự kiện tải / lỗi:

$.fn.extend({
    loadImg: function(url, timeout) {
        // init deferred object
        var defer = $.Deferred(),
            $img = this,
            img = $img.get(0),
            timer = null;

        // define load and error events BEFORE setting the src
        // otherwise IE might fire the event before listening to it
        $img.load(function(e) {
            var that = this;
            // defer this check in order to let IE catch the right image size
            window.setTimeout(function() {
                // make sure the width and height are > 0
                ((that.width > 0 && that.height > 0) ? 
                    defer.resolveWith : 
                    defer.rejectWith)($img);
            }, 1);
        }).error(function(e) {
            defer.rejectWith($img);
        });

        // start loading the image
        img.src = url;

        // check if it's already in the cache
        if (img.complete) {
            defer.resolveWith($img);
        } else if (0 !== timeout) {
            // add a timeout, by default 15 seconds
            timer = window.setTimeout(function() {
                defer.rejectWith($img);
            }, timeout || 15000);
        }

        // return the promise of the deferred object
        return defer.promise().always(function() {
            // stop the timeout timer
            window.clearTimeout(timer);
            timer = null;
            // unbind the load and error event
            this.off("load error");
        });
    }
});

Sử dụng:

var image = $('<img />').loadImg('http://www.google.com/intl/en_com/images/srpr/logo3w.png')
.done(function() {
    alert('image loaded');
    $('body').append(this);
}).fail(function(){
    alert('image failed');
});

Xem nó hoạt động tại: http://jsfiddle.net/roberkules/AdWZj/


Điều đó nghe có vẻ tuyệt vời. Bạn có thể vui lòng cho một ví dụ chính xác về thời điểm mã của bạn thích hợp với img.onload và img.onerror không? Có phải mã của bạn chỉ nhằm xử lý những thiếu sót dường như trong xử lý lỗi jQuery mà tôi vừa được thông báo: lỗi đó không kích hoạt trong IE nếu không có phần mở rộng tệp?
mplungjan

ý tưởng thú vị. để biết khi nào hình ảnh hoàn thành dễ dàng. Nhưng, điều gì sẽ xảy ra nếu ảnh không tải được. Tôi đang tìm cách để biết liệu tải hình ảnh có bị lỗi hay không. và bạn đã cho tôi ý tưởng về thời gian chờ khi tải nó. +1 cho điều đó
sồi

1
@oak thời gian chờ chỉ nên dự phòng. hầu hết các trình duyệt sẽ kích hoạt một errorsự kiện được xử lý bởi .error(function(e) { defer.rejectWith($img); }). Nếu bạn nhìn vào jsFiddle bạn sẽ thấy rằng các http://www.google.com/abc.png not foundvăn bản được hiển thị ngay lập tức trong cửa sổ kết quả (không chờ đợi một thời gian chờ, vì sự kiện lỗi đá vào)
roberkules

lưu ý rằng đối với jquery để nâng cao .error hai điều phải là 1. xử lý nhưng được đặt trước khi lỗi được nêu ra. 2. .error chỉ xử lý giao thức http chứ không phải tệp: // vì vậy bạn sẽ không gặp lỗi ở đó ..
oak

trong ví dụ mã của tôi, trình xử lý thành công / lỗi được đặt trước khi gán chính xác thuộc tính src vì lý do đó. về file://hạn chế - tôi không bao giờ cần liên kết hình ảnh bằng giao thức tệp và tôi không nghĩ là cần nhiều.
roberkules

1

Chức năng này kiểm tra xem hình ảnh có được tải hay không dựa trên việc có các kích thước có thể đo được. Kỹ thuật này hữu ích nếu tập lệnh của bạn đang thực thi sau khi một số hình ảnh đã được tải.

imageLoaded = function(node) {
    var w = 'undefined' != typeof node.clientWidth ? node.clientWidth : node.offsetWidth;
    var h = 'undefined' != typeof node.clientHeight ? node.clientHeight : node.offsetHeight;
    return w+h > 0 ? true : false;
};

Tôi phát hiện ra rằng giải pháp này có thể yêu cầu không có lề hoặc khoảng đệm trên hình ảnh và văn bản thay thế của một chuỗi trống được cung cấp. Trong hầu hết các trường hợp, nó hoạt động như dự định. Nó sẽ chỉ không thành công nếu kích thước của hình ảnh không tải lớn hơn 0.
Ralph Ritoch

1

Tôi thấy điều này hiệu quả với tôi

document.querySelector("img").addEventListener("load", function() { alert('onload!'); });

Frank Schwieterman, người đã nhận xét về câu trả lời được chấp nhận. Tôi phải đặt cái này ở đây, nó quá giá trị ...


0

Chúng tôi đã phát triển một trang trong đó nó tải một số hình ảnh và sau đó thực hiện các chức năng khác chỉ sau khi hình ảnh được tải. Đó là một trang web bận rộn tạo ra rất nhiều lưu lượng truy cập. Có vẻ như tập lệnh đơn giản sau đã hoạt động trên thực tế trên tất cả các trình duyệt:

$(elem).onload = function() {
    doSomething();
}

NHƯNG ĐÂY LÀ VẤN ĐỀ TIỀM NĂNG CHO IE9!

Trình duyệt DUY NHẤT mà chúng tôi đã báo cáo sự cố là IE9. Chúng ta không ngạc nhiên sao? Có vẻ như cách tốt nhất để giải quyết vấn đề đó là không chỉ định một src cho hình ảnh cho đến khi SAU KHI chức năng onload đã được xác định, như sau:

$(elem).onload = function() {
    doSomething();
}
$(elem).attr('src','theimage.png');

Có vẻ như IE 9 đôi khi sẽ không ném onloadsự kiện vì bất cứ lý do gì. Các giải pháp khác trên trang này (chẳng hạn như giải pháp của Evan Carroll chẳng hạn) vẫn không hoạt động. Về mặt logic, điều đó đã kiểm tra xem trạng thái tải đã thành công chưa và kích hoạt chức năng và nếu không, thì hãy đặt trình xử lý tải lên, nhưng ngay cả khi bạn làm điều đó, chúng tôi đã chứng minh trong thử nghiệm rằng hình ảnh có thể tải giữa hai dòng js đó. xuất hiện không được tải đến dòng đầu tiên và sau đó tải trước khi bộ xử lý tải lên được đặt.

Chúng tôi nhận thấy rằng cách tốt nhất để có được những gì bạn muốn là không xác định src của hình ảnh cho đến khi bạn đặt trình onloadkích hoạt sự kiện.

Chúng tôi chỉ mới ngừng hỗ trợ IE8 gần đây nên tôi không thể nói về các phiên bản trước IE9, nếu không, trong số tất cả các trình duyệt khác đã được sử dụng trên trang web - IE10 và 11 cũng như Firefox, Chrome, Opera, Safari và bất cứ thứ gì trình duyệt di động mà mọi người đang sử dụng - cài đặt srctrước khi gán onloadtrình xử lý thậm chí không phải là một vấn đề.


0

Tôi có thể đề xuất một giải pháp CSS thuần túy hoàn toàn không?

Chỉ cần có Div mà bạn muốn hiển thị hình ảnh. Đặt hình ảnh làm nền. Sau đó có tài sản background-size: coverhoặc background-size: containtùy thuộc vào cách bạn muốn nó.

coversẽ cắt hình ảnh cho đến khi các cạnh nhỏ hơn che hộp. containsẽ giữ toàn bộ hình ảnh bên trong div, để lại cho bạn khoảng trống ở hai bên.

Kiểm tra đoạn mã dưới đây.

div {
  height: 300px;
  width: 300px;
  border: 3px dashed grey;
  background-position: center;
  background-repeat: no-repeat;
}

.cover-image {
  background-size: cover;
}

.contain-image {
  background-size: contain;
}
<div class="cover-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>
<br/>
<div class="contain-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>


0

Tôi thấy rằng giải pháp đơn giản này phù hợp nhất với tôi:

        function setEqualHeight(a, b) {
            if (!$(a).height()) {
                return window.setTimeout(function(){ setEqualHeight(a, b); }, 1000);
            }
            $(b).height($(a).height());
        }

        $(document).ready(function() {
            setEqualHeight('#image', '#description');
            $(window).resize(function(){setEqualHeight('#image', '#description')});
        });
    </script>
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.