【问题标题】:How can I determine if an image has loaded, using Javascript/jQuery?如何使用 Javascript/jQuery 确定图像是否已加载?
【发布时间】:2010-09-20 18:32:19
【问题描述】:

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

所以 HTML 中会有这样的内容:

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

我有没有办法确定img 标签中的src 图像是否已下载?

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

现在我只是检查照片的高度是否小于 150,并假设如果是,它只是替代文本。但这是一个相当大的技巧,如果照片的高度小于 150 像素(在我的特定情况下不太可能),或者 alt 文本的高度超过 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));
  }

});

【问题讨论】:

  • 这太老了,您已经接受了答案,所以我将在这里发表评论。为什么不能使用 jQuery 插件“onImagesLoad”?而且,无论是否使用 jQuery,使用 Javascript 在图像样式中设置 max-widthmax-height 有什么问题?然后,您可以通过将最大宽度/高度设置为视口宽度/高度的大小来避免您需要编写的所有代码。
  • @jon.wd7:我不熟悉那个插件,它可能早在 08 年就没有了。至于最大宽度和最大高度,有两件事:1)IE 不支持它们(我不确定 IE 8); 2)如果视口改变大小(窗口大小调整等),那么我仍然需要javascript来改变最大宽度/最大高度(尽管如果我使用“100%”而不是像素测量,我可能不会)
  • 根据 quirksmode.org 的说法,IE7 和 IE8 肯定支持它。所以我不确定你的问题。对于这样的小事,我个人不支持 IE6,所以他们看到的和没有启用 JS 的用户看到的一样。当然,您需要在调整大小时重置 max-widthmax-height。但这是一项相当容易的任务,实际上是使用.resize() 的单行代码。
  • complete 属性提供了了解图像是否已加载的必要方式。
  • @Adrien,Mozilla 现在 shows 已完成,所有主流浏览器都支持,除了 Andoid(未知)。

标签: javascript jquery image


【解决方案1】:

要么添加一个事件侦听器,要么让图像通过 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 中有效,但我不知道它在任何其他浏览器中也有效,或者你可以假设它是什么......我几周前只是在研究这个......跨度>
  • 我已经在 IE6、IE7、FF3、Opera9、Safair (Windows Beta) 和 Chrome (Windows Beta) 中进行了测试。
  • 不鼓励乱发行为和内容。事件应该使用 Javascript,而不是 HTML。
  • 他的评论是相关的,因为我们没有被困在 2008 年。人们仍在阅读这篇文章,即使它在 08 年被认为不是坏做法,你也不希望人们现在认为它是好的做法。
  • document.querySelector("img").addEventListener("load", function() { alert('onload!'); });
【解决方案2】:

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

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

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

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

【讨论】:

  • 使用jQuery(this) 而不是$(this) 以更好地与其他库兼容(jquery 不拥有 $),尤其是当您在 html 中有 JavaScript 时。
【解决方案3】:

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

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

根据.load() 上的文档

【讨论】:

  • 我打算用这样的建议添加一个答案,很高兴我在编码之前看到了这个答案。基本上,您的处理程序需要在设置处理程序之前首先检查图像是否已加载。如果它已经加载,立即触发回调。这就是$.ready 所做的。我本来建议只检查宽度,但这有问题,我真的很喜欢这个解决方案。
【解决方案4】:

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

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

【讨论】:

  • 该网站仍然适用于没有 Javascript 的人,他们只需滚动即可查看所有图像。
【解决方案5】:

根据最近对您原始问题的回答之一

$(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,请使用标志来记住已加载图像。
【解决方案6】:

尝试类似:

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

【讨论】:

  • 谢谢。但是,有可能在此之前图像已经加载,在这种情况下不会触发 load 事件。
  • 在图片标签之后设置这个事件的脚本标签怎么样?使用 ready 的原因是确保整个文档都已加载,在这种情况下这是不必要的,对吧?
【解决方案7】:

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

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

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

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

插件很棒:

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

【讨论】:

  • 似乎有点重 5KB 缩小只是为了检查 img 加载。应该是一种更简单的打火机方法......
【解决方案8】:

我发现这对我有用

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

这完全归功于 Frank Schwieterman,他对接受的答案发表了评论。不得不放这里,太贵重了……

【讨论】:

    【解决方案9】:

    这个有cmet吗?

    ...

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

    ...

    似乎无处不在...

    【讨论】:

    • 使用setTimeout是不好的做法
    【解决方案10】:

    我刚刚创建了一个 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/

    【讨论】:

    • 听起来很棒。您能否给出一个确切的例子,说明您的代码何时优于 img.onload 和 img.onerror?您的代码是否仅用于处理我刚刚获悉的 jQuery 错误处理的看似缺点:如果没有文件扩展名,该错误不会在 IE 中触发?
    • 有趣的想法。所以知道图像何时完成很容易。但是,如果无法加载图像怎么办。我正在寻找一种方法来知道加载图像是否失败。你给了我超时加载它的想法。为此 +1
    • @oak 超时应该只是一个后备。大多数浏览器应该触发由.error(function(e) { defer.rejectWith($img); }) 处理的error 事件。如果您查看 jsFiddle,您将看到 http://www.google.com/abc.png not found 文本立即显示在结果窗格中(不等待超时,因为错误事件已启动)
    • 请注意,jquery 引发 .error 的两件事应该是 1. 句柄,但要在引发错误之前设置。 2. .error 只处理 http 协议而不是 file:// 所以你不会在那里出错..
    • 在我的代码示例中,成功/错误处理程序是在完全为此原因分配 src 属性之前设置的。关于file:// 限制 - 我从来不需要使用文件协议链接图像,我认为没有太多需要。
    【解决方案11】:

    此函数根据可测量的尺寸检查图像是否已加载。如果您的脚本在某些图像已经加载后执行,则此技术很有用。

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

    【讨论】:

    • 我发现此解决方案可能要求图像上没有边距或填充,并提供空字符串的替代文本。但在大多数情况下,它按预期工作。仅当卸载图像的大小大于零时才会失败。
    【解决方案12】:

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

    $(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 和人们使用的任何移动浏览器——在分配 onload 处理程序之前设置 src 甚至都不是问题。

    【讨论】:

      【解决方案13】:

      我可以推荐一个纯 CSS 解决方案吗?

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

      cover 将裁剪图像,直到较小的边覆盖框。 contain 会将整个图像保留在 div 中,并在两侧留出空格。

      检查下面的sn-p。

      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>

      【讨论】:

        【解决方案14】:

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

                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>
        

        【讨论】:

          【解决方案15】:

          【讨论】:

          猜你喜欢
          • 2011-12-04
          • 2015-07-13
          • 2014-11-30
          • 1970-01-01
          • 2011-05-28
          • 2010-11-10
          • 1970-01-01
          • 2014-01-04
          相关资源
          最近更新 更多