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

Posted

技术标签:

【中文标题】如何使用 Javascript/jQuery 确定图像是不是已加载?【英文标题】: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"
     
     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"
     
     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(未知)。 【参考方案1】:

要么添加一个事件侦听器,要么让图像通过 onload 宣布自己。然后从那里找出尺寸。

<img id="photo"
     onload='loaded(this.id)'
     src="a_really_big_file.jpg"
     
     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!");
)

插件很棒:

    用于检查包含许多图像的容器 用于检查 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】:

image.complete 可能是另一种选择 https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。 Answers that are little more than a link may be deleted

以上是关于如何使用 Javascript/jQuery 确定图像是不是已加载?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:如何获取文件上传输入字段的“值”

Javascript/jQuery/JSON/localStorage 游戏,无法按数字排序排名表

如何使用 jquery/javascript 将文本插入 json [重复]

如何使用 JavaScript/JQuery 创建一个简单的地图 [重复]

如何使用 PHP 或 JavaScript/jQuery 禁用地址栏?

Rails如何检测是不是使用javascript / jQuery插入了部分