【问题标题】:How to show a spinner while loading an image via JavaScript如何在通过 JavaScript 加载图像时显示微调器
【发布时间】:2010-09-08 06:11:43
【问题描述】:

我目前正在开发一个 Web 应用程序,该应用程序有一个显示单个图表(.png 图像)的页面。在该页面的另一部分,有一组链接,当点击这些链接时,整个页面会重新加载并且看起来与之前完全相同,除了页面中间的图表。

我想要做的是当点击页面上的链接时,页面上的图表会发生变化。这将大大加快速度,因为页面大约有 100kb 大,并且真的不想为了显示这个而重新加载整个页面。

我一直在通过 JavaScript 执行此操作,到目前为止,它可以使用以下代码

document.getElementById('chart').src = '/charts/10.png';

问题是当用户点击链接时,图表可能需要几秒钟的时间才会改变。这会让用户认为他们的点击没有做任何事情,或者系统响应缓慢。

我想要发生的是显示一个微调器/颤动器/状态指示器,代替加载图像时的位置,所以当用户点击链接时,他们知道至少系统已经接受了他们的输入并且正在做关于它的东西。

我尝试了一些建议,甚至使用 psudo 超时来显示微调器,然后快速返回图像。

我的一个好建议是使用以下内容

<img src="/charts/10.png" lowsrc="/spinner.gif"/>

这将是理想的,除了微调器明显小于正在显示的图表。

还有其他想法吗?

【问题讨论】:

  • 对于桌面用户,您还可以更改光标以显示正在发生的事情。您必须使用一些 CSS,如 body.waiting{cursor: wait;},然后使用 javascript 切换它:document.body.classList.add('waiting'); 和图像加载:document.body.classList.remove('waiting');

标签: javascript jquery dom


【解决方案1】:

我使用类似这样的方法来预加载图像,然后在图像加载完成后自动回调我的 javascript。您需要在设置回调之前检查完成,因为图像可能已经被缓存并且它可能不会调用您的回调。

function PreloadImage(imgSrc, callback){
  var objImagePreloader = new Image();

  objImagePreloader.src = imgSrc;
  if(objImagePreloader.complete){
    callback();
    objImagePreloader.onload=function(){};
  }
  else{
    objImagePreloader.onload = function() {
      callback();
      //    clear onLoad, IE behaves irratically with animated gifs otherwise
      objImagePreloader.onload=function(){};
    }
  }
}

【讨论】:

    【解决方案2】:

    您可以显示一个静态图像,该图像提供optical illusion of a spinny-wheel, like these

    【讨论】:

      【解决方案3】:

      使用 jQueryload() 方法,可以轻松地在图像加载后立即执行操作:

      $('img.example').load(function() {
        $('#spinner').fadeOut();
      });
      

      见:http://api.jquery.com/load-event/

      【讨论】:

      • load 以这种方式的用法现在已弃用(在 3.0 中已删除)并已替换为加载事件
      【解决方案4】:

      使用 setTimeout() 函数 (More info) 的强大功能 - 这允许您设置一个计时器以在将来触发函数调用,并且调用它不会阻止执行当前/其他功能(异步)。

      在图表图像上方放置一个包含微调器的 div,并将其 css 显示属性设置为无:

      <div>&nbsp;<img src="spinner.gif" id="spinnerImg" style="display: none;" /></div>
      

      当微调器被隐藏时,nbsp 会阻止 div 折叠。没有它,当您切换微调器的显示时,您的布局将“抽搐”

      function chartOnClick() {
        //How long to show the spinner for in ms (eg 3 seconds)
        var spinnerShowTime = 3000
      
        //Show the spinner
        document.getElementById('spinnerImg').style.display = "";
      
        //Change the chart src
        document.getElementById('chart').src = '/charts/10.png';
      
        //Set the timeout on the spinner
        setTimeout("hideSpinner()", spinnerShowTime);
      }
      
      function hideSpinner() {
        document.getElementById('spinnerImg').style.display = "none";
      }
      

      【讨论】:

      • setTimeout 不需要引号中的第一个参数 - 您可以这样称呼它: setTimeout(hideSpinner, spinnerShowTime);这样就省去了让 JS 解释器评估字符串的步骤,这只是开销。
      • 在这种情况下它会更快,但是在您想将参数传递给函数的情况下,我发现将事物包含在 dbleQts 中以减少问题(我想以牺牲易读性为代价)
      • @iAn 您在答案中添加的链接已损坏
      【解决方案5】:

      使用 CSS 将加载动画设置为图像容器的居中背景图像。

      然后在加载新的大图时,先将src设置为预加载的透明1像素gif。

      例如

      document.getElementById('mainimg').src = '/images/1pix.gif'; document.getElementById('mainimg').src = '/images/large_image.jpg';

      在加载 large_image.jpg 时,背景将通过 1pix 透明 gif 显示。

      【讨论】:

        【解决方案6】:

        根据 Ed 的回答,我希望看到类似的内容:

        function PreLoadImage( srcURL, callback, errorCallback ) {
             var thePic = new Image();
        
             thePic.onload = function() {
                  callback();
                  thePic.onload = function(){};
             }
        
             thePic.onerror = function() {
                  errorCallback();
             }
             thePic.src = srcURL;
        }
        

        您的回调可以在适当的位置显示图像并处理/隐藏微调器,并且 errorCallback 可以防止您的页面“沙滩球”。所有事件驱动,没有计时器或轮询,而且您不必添加额外的 if 语句来检查图像是否在您设置事件时完成加载 - 因为它们是预先设置的,无论如何图像加载速度很快。

        【讨论】:

          【解决方案7】:

          前段时间我写了一个jQuery插件来处理自动显示一个微调器http://denysonique.github.com/imgPreload/

          查看其源代码应该可以帮助您检测何时显示微调器并将其显示在加载图像的中心。

          【讨论】:

            【解决方案8】:

            我喜欢 @duddle 的 jquery 方法,但发现 load() 并不总是被调用(例如从 IE 的缓存中检索图像时)。我改用这个版本:

            $('img.example').one('load', function() {
              $('#spinner').remove();
            }).each(function() {
              if(this.complete) {
                $(this).trigger('load');
              }
            });
            

            这最多调用一次加载,如果已经完成加载则立即调用。

            【讨论】:

            • .one() 应该是 .on()
            • 不,你错了。在这种情况下,我只想触发一次加载。 api.jquery.com/one
            【解决方案9】:

            将微调器放在与图表大小相同的 div 中,您知道高度和宽度,因此您可以使用相对定位将其正确居中。

            【讨论】:

              【解决方案10】:

              除了 lowsrc 选项,我还在img 的容器上使用了background-image

              【讨论】:

                【解决方案11】:

                请注意,如果图像 src 不存在(http 404 错误),也会调用回调函数。为避免这种情况,您可以检查图像的宽度,例如:

                if(this.width == 0) return false;
                

                【讨论】:

                  【解决方案12】:

                  @iAn 的解决方案对我来说看起来不错。我唯一要改变的是不使用 setTimeout,而是尝试挂钩图像“加载”事件。这样,如果图片的下载时间超过 3 秒,您仍然会获得微调器。

                  另一方面,如果下载时间较短,您将获得微调器的时间不到 3 秒。

                  【讨论】:

                  • 这就是在图像上使用 Load 事件的陷阱——如果你找到一个连接速度很快的人,那么微调器就会再次打开和关闭。您必须考虑到微调器实际上有两个目的:不仅是“请稍候”,还有“某事已经发生”
                  【解决方案13】:

                  我会添加一些随机数字以避免浏览器缓存。

                  【讨论】:

                  • 为什么要避免浏览器的缓存?
                  • 不知道我在想什么 :) 那是 7 年前。我敢打赌这是有充分理由的,否则我不会建议这样做。
                  猜你喜欢
                  • 2022-06-14
                  • 1970-01-01
                  • 2019-11-16
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-07-27
                  相关资源
                  最近更新 更多