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


85

我正在编写一些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,并假设是alt文字。但这是一个很不错的技巧,如果照片的高度小于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事件设置了回调,则存在事件未触发的风险,因此我直接在image标签上定义了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));
  }

});

1
这太老了,您已经接受了答案,所以我只在这里发表评论。为什么不能使用jQuery插件“ onImagesLoad”?而且,无论是否使用jQuery,设置max-widthmax-heightJava图像样式设置都有什么问题?然后,通过将最大宽度/高度设置为视口宽度/高度的大小,可以避免编写所有代码。

@ jon.wd7:我对该插件不熟悉,它可能早在08年就已推出。至于最大宽度和最大高度,有两件事:1)IE不支持它们(嗯,我不确定IE 8)。2)如果视口更改大小(窗口大小已调整,等等),那么我仍然需要JavaScript来更改最大宽度/最大高度(尽管如果我使用“ 100%”而不是像素尺寸,我可能不会)
基普

据quirksmode.org称,IE7和IE8绝对支持它。所以我不确定你的问题。我个人不支持IE6这样的小功能,因此他们看到的内容与未启用JS的用户将看到的内容相同。当然,您将需要重置max-widthmax-height调整大小。但这是一项非常容易的任务,.resize()实际上是一个单线使用。

3
完整的属性给出知道图像是否已经被加载的方式势在必行。
BorisOkunskiy 2013年

1
@ Adrien,Mozilla现在显示所有主要浏览器都支持的完整信息,但Andoid(未知)除外。
奥利弗·博克

Answers:


33

添加事件侦听器,或让图像通过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" />

根据规范,onload只是body和frameset元素的事件;就是说,我认为这可以在IE中使用,但是我不知道它可以在任何其他浏览器中使用,或者您可以假设它是...某些事情我只是在几周前才研究过……
Jason彩旗

我已经在IE6,IE7,FF3,Opera9,Safair(Windows Beta)和Chrome(Windows Beta)中对其进行了测试。
Kip

9
不鼓励混乱的行为和内容。事件应使用Javascript而不是HTML来应用。
dionyziz 2012年

10
他的评论很有意义,因为我们并没有在2008年陷入困境。人们仍然读到这句话,即使在08年也被认为不是坏习惯,您也不希望人们现在认为它的好习惯。
Spoeken 2013年

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

14

使用jQuery数据存储,您可以定义“已加载”状态。

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

然后在其他地方您可以执行以下操作:

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

2
使用jQuery(this)代替以$(this)获得更好的与其他库的兼容性(jquery不拥有$),尤其是当您的HTML中包含JavaScript时。
约翰·木兰

11

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

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

根据.load()上的文档


2
我打算添加一个带有这样建议的答案,很高兴在编码之前看到了这个答案。基本上,您的处理程序需要在设置处理程序之前先检查是否已加载映像。如果已加载,请立即触发回调。这是什么$.ready呢。我只是建议检查宽度,但这有问题,我真的很喜欢这种解决方案。
Juan Mendes 2013年

5

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

在可访问性方面,您的网站是否仍适用于没有javascript的用户?您可能需要为img标签提供正确的src,为您添加dom ready处理程序以运行您的js:清除图片src(将其固定为css并设置高度,以防止页面闪烁),然后设置img加载处理程序,然后将src重置为正确的文件。这样,您可以覆盖所有基础:)


该网站仍适用于没有Javascript的人,他们只需滚动即可查看所有图像。
Kip

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,请使用标志来记住图像已加载。


拿住。这个答案可能会在ie8及更低版本中引起严重的循环,因为img.complete并非总是由浏览器正确设置的。如果必须支持ie8,请使用标志来记住图像已加载。
commonpike

2

尝试类似的方法:

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

6
谢谢。但是,在这种情况发生之前,可能已经加载了图像,在这种情况下,不会触发加载事件。
Kip

在图片标签之后立即设置此事件的脚本标签如何?使用ready的原因是要确保整个文档都已加载,在这种情况下这是不必要的,对吗?
杰森·古玛

2

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

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

内部包含许多图像的容器的用法:

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

该插件很棒:

  1. 用于检查带有许多图像的容器
  2. 用于检查img以查看其是否已加载

似乎有点笨重的5KB,只能检查img加载了。应该是可用的更轻便的方法...
cdalxndr

1

对此有何评论?

...

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

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

doShow();

...

似乎无处不在...


这是不好的做法setTimeout
cdalxndr

1

我刚刚创建了一个jQuery函数来使用jQuery的Deferred Object加载图像,这使得对load / error事件的反应非常容易:

$.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/


听起来不错。您能否给出一个确切的示例说明何时您的代码比img.onload和img.onerror更可取?您的代码是否仅用于解决我刚刚被告知的jQuery错误处理的表面缺陷:如果没有文件扩展名,该错误不会在IE中触发?
mplungjan

有趣的主意。因此知道何时轻松完成图像。但是,如果无法加载图像,该怎么办。我正在寻找一种方法来确定图像加载是否失败。并且您给了我超时加载的想法。为此+1
橡树

1
@oak超时应该只是一个备用。大多数浏览器应触发error由处理的事件.error(function(e) { defer.rejectWith($img); })。如果您查看jsFiddle,您会看到http://www.google.com/abc.png not found文本立即显示在结果窗格中(不等待超时,因为发生了错误事件)
roberkules 2014年

请注意,对于jquery引发.error,应该有两件事:1.句柄,但应在引发错误之前进行设置。2. .error只处理HTTP协议,而不是文件://这样你就不会得到错误有..
橡树

在我的代码示例中,正是由于这个原因,才在成功分配src属性之前设置成功/错误处理程序。关于file://限制-我从来不需要使用文件协议链接图像,我认为没有太多需要。
roberkules 2014年

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

我发现此解决方案可能要求图像上没有空白或填充,并提供了空字符串的替代文本。但是,在大多数情况下,它可以按预期工作。仅当卸载的图像的大小大于零时,它才会失败。
拉尔夫·里托奇

1

我发现这对我有用

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

归功于Frank Schwieterman,他对接受的答案进行了评论。我不得不把它放在这里,这太有价值了...


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处理程序之前设置都不是问题。


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

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

        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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.