如何使用Javascript / jQuery确定图像是否已加载?

时间:2008-11-04 20:44:38

标签: javascript jquery image

我正在编写一些Javascript来调整大图像的大小以适应用户的浏览器窗口。 (遗憾的是,我无法控制源图像的大小。)

所以像这样的东西会出现在HTML中:

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

我有办法确定src标记中的img图片是否已下载?

我需要这个,因为如果在浏览器加载图像之前执行了$(document).ready(),我就会遇到问题。 $("#photo").width()$("#photo").height()将返回占位符的大小(替代文字)。就我而言,这就像134 x 20。

现在我只是检查照片的高度是否小于150,并假设如果是这样,它只是替代文字。但这是一个非常黑客,如果一张照片的高度低于150像素(在我的特定情况下不太可能),或者如果替代文字高度超过150像素(可能发生在一个小的浏览器窗口上),它就会破裂


修改:对于任何想要查看代码的人:

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

});

更新:感谢您的建议。如果我为$("#photo").load事件设置回调,则存在未触发事件的风险,因此我直接在图像标记上定义了onLoad事件。为了记录,这里是我最终的代码:

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

然后在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));
  }

});

15 个答案:

答案 0 :(得分:31)

添加事件侦听器,或让图像通过onload声明自己。然后从那里找出尺寸。

<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" />

答案 1 :(得分:14)

使用jquery data store,您可以定义“已加载”状态。

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

然后在其他地方你可以做到:

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

答案 2 :(得分:9)

正确答案是使用event.special.load

  

如果从浏览器缓存加载图像,则可能无法触发加载事件。为了解释这种可能性,我们可以使用特殊的加载事件,如果图像准备就会立即触发。 event.special.load目前作为插件提供。

根据.load()

上的文档

答案 3 :(得分:5)

你想做Allain所说的,但要注意有时候图像会在dom准备好之前加载,这意味着你的加载处理程序不会触发。最好的方法是按照Allain的说法进行操作,但在附加加载程序后用javascript设置图像的src。这样你就可以保证它会被激发。

在可访问性方面,您的网站是否仍适用于没有javascript的用户?你可能想给img标签正确的s​​rc,附上你的dom ready处理程序来运行你的js:清除图像src(用css给它一个固定的和高度以防止页面闪烁),然后设置你的img加载处理程序,然后将src重置为正确的文件。这样你就涵盖了所有基础:)

答案 4 :(得分:4)

根据您最初对原始问题的评论之一

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

警告此答案可能会导致ie8及更低版本出现严重循环,因为浏览器并未始终正确设置img.complete。如果必须支持ie8,请使用标记来记住加载的图像。

答案 5 :(得分:3)

尝试类似:

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

答案 6 :(得分:2)

对此有何评论?

...

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

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

doShow();

...

似乎无处不在......

答案 7 :(得分:2)

有一个名为“imagesLoaded”的jQuery插件,它提供了一种跨浏览器兼容的方法来检查元素的图像是否已被加载。

网站:https://github.com/desandro/imagesloaded/

用于内部有许多图像的容器:

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

该插件很棒:

  1. 用于检查包含许多图像的容器
  2. 用于检查img是否已加载

答案 8 :(得分:2)

我发现这对我有用

document.querySelector("img").addEventListener("load", function() { alert('onload!'); });
信用完全归功于Frank Schwieterman,他评论了接受的答案。我不得不把它放在这里,它太有价值......

答案 9 :(得分:1)

我刚创建了一个jQuery函数来使用jQuerys Deferred Object加载图像,这使得它很容易对加载/错误事件做出反应:

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

<强>用法:

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

查看工作地点:http://jsfiddle.net/roberkules/AdWZj/

答案 10 :(得分:1)

此功能根据具有可测量的尺寸检查是否加载了图像。如果在加载了某些图像后执行脚本,此技术非常有用。

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

答案 11 :(得分:0)

我们开发了一个页面,其中加载了许多图像,然后仅在加载图像后执行其他功能。这是一个繁忙的网站,产生了大量的流量。似乎以下简单的脚本几乎适用于所有浏览器:

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

但这是IE9的潜在问题!

我们报告过的唯一浏览器是IE9。我们不感到惊讶吗?似乎解决问题的最佳方法是在定义onload函数之后不将src分配给图像,如下所示:

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

似乎IE 9有时不会因任何原因抛出onload事件。此页面上的其他解决方案(例如Evan Carroll的解决方案)仍无效。逻辑上,它检查了加载状态是否已经成功并触发了该功能,如果它不是,则设置onload处理程序,但即使你这样做,我们在测试中证明图像可以在这两行之间加载因此,js显示未加载到第一行,然后在设置onload处理程序之前加载。

我们发现获得所需内容的最佳方法是在设置onload事件触发器之前不定义图像的src。

我们最近才停止支持IE8,所以我不能说IE9之前的版本,否则,在网站上使用的所有其他浏览器 - IE10和11以及Firefox,Chrome, Opera,Safari以及人们使用的任何移动浏览器 - 在分配src处理程序之前设置onload甚至不是问题。

答案 12 :(得分:0)

我可以完全建议一个纯CSS解决方案吗?

只有一个要显示图像的Div。将图像设置为背景。然后根据需要使用属性background-size: coverbackground-size: contain

cover:将裁切图像,直到较小的一侧覆盖盒子为止。 contain:会将整个图像保留在div内,在两侧留有空格。

检查下面的代码段。

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 style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)" class="cover-image">
</div>
<br/>
<div style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)" class="contain-image">
</div>

答案 13 :(得分:0)

我发现这个简单的解决方案最适合我:

        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>

答案 14 :(得分:0)