5

我有几个带有背景图像的 div。我想知道如何使用 gif 图像预加载这些背景图像,因为一些背景图像非常大。执行以下操作不起作用:

HTML:

<div id="glykopeels" onload="loadImage()">Glykopeels Content</div>
<div id="facials" onload="loadImage2()">Facials Content</div>

CSS:

#glykopeels{
        background: #ebebeb url(http://lamininbeauty.co.za/images/products/preloader.gif) no-repeat top right;
        background-size: contain;
    }
#facials{
    background: #ebebeb url(http://lamininbeauty.co.za/images/products/preloader.gif) no-repeat top right;
    background-size: contain;
    }

JS:

function loadImage(){
        document.getElementById('glykopeels').style.background = '#ebebeb url(http://lamininbeauty.co.za/images/products/glykopeel.jpg);';
    }
function loadImage2(){
        document.getElementById('facials').style.background = '#ebebeb url(http://lamininbeauty.co.za/images/products/facial.jpg);';
    }

我猜想在 onload 函数中为该元素定义一个不同的 ID 并为该新 ID 定义 css 是另一种可能性吗?因此仅更改 onload 函数中该元素的 id?

谢谢

4

3 回答 3

5

首先: div 没有 onload 属性。编辑:请阅读下面的评论,非常有趣!

其次,您应该将 url 放在引号之间(如果需要,将它们转义):url('http://lamininbeauty.co.za/images/products/facial.jpg')

第三,没有名为 的图像preloader.gif,但有一个名为 的图像loader.gif,因此我使用该图像在底部的 jsfiddle 演示链接中为我的解决方案“修复”您的 css 部分。

在 SO 的服务器迁移期间,我为您编写了一个简单的自定义函数,它完全符合您的要求。
IE6和 FF12 中测试。
要对此进行测试:请清除您的浏览器缓冲区,否则您将看不到它的实际效果(它会运行得太快),因为图像可能会在第二个视图上被缓冲(再次,非常适合您的目标)!

JavaScript:

var repBg=function(a, t){ t=t||'*';  // by GitaarLAB
        var c=document.getElementsByTagName(t), i=c.length, r=[];
        while(i--){if (c[i].getAttribute(a)){r.push(c[i]);}} c=r; i=c.length;
        repBg.exec=function(){
            c[this['data-i']].style.background="#ebebeb url('"+this.src+"') no-repeat top right";
        };
        while(i--){ if (c[i].getAttribute(a)) {
            r=new Image();
            r.onload=repBg.exec;
            r['data-i']=i;
            r.src=c[i].getAttribute(a);
        }}  
};

// one could run repBg onload, but better to run it when the image has actually loaded, see html!
// window.onload=function(){  repBg('data-bg_img','div');  };

在您的 BODY 中:将属性“data-bg_img”(根据 html5 约定,以 data- 开头)添加到您要使用此技术的元素中,并使其包含您的背景 url,如下所示:

<div id="glykopeels" data-bg_img="http://lamininbeauty.co.za/images/products/glykopeel.jpg">Glykopeels Content</div>

身体中的“可选”初始化:

<!--
trigger the replace background function when the loader image has actually loaded!
rewriting the onload with nothing to prevent infinite loop in IE6 (and greater?) !!
-->
<img src="http://lamininbeauty.co.za/images/products/loader.gif" style="display:none;" onload="this.onload=null; repBg('data-bg_img','div');">

手动/说明:
图像确实有一个加载事件,所以我们在 html 中放置一个加载图像(在底部),这将触发它自己的加载事件,repBg()一旦浏览器实际下载了这个加载图像就会调用!!!

该函数repBg()最多需要 2 个参数:

  • 包含应选择的属性的第一个强制字符串,
  • 第二个可选参数可以定义标记名(以限制第一个参数)。

当被调用时,函数repBg()将在主体中搜索符合第二个参数的 elementTagNames,或者*然后使用第一个参数过滤它们。
对于保留在过滤后的 htmlObjectCollection 中的每个 htmlObject,将创建一个新图像(不附加到正文),其中 htmlObject 的属性值 (url) 对应于函数的第一个参数作为图像源,以及 htmlObjectCollection 的引用 id (attribute data-id) 以供参考。
一旦这些图像加载,它们就会触发它们的 onload 事件:调用repBgexec方法,用新加载的(大)背景图像(以及你的 css 的其余部分)替换引用的 htmlObject 的背景。为了进一步模块化,您可以扩展该功能。

最后,请注意:背景图像按照它们出现在源代码中的顺序加载,也就是您期望的工作方式!

你可以在这个小提琴中看到它的作用:http://jsfiddle.net/epdDa/


更新版本 2:优雅的回退!和复制粘贴 NOBRAIN 解决方案
我的第一个解决方案没有提供优雅的回退,这让我很生气。所以我做了一个不同的解决方案来提供优雅的回退。在IE6
和 FF12 中也经过全面测试它的工作原理如下: 在您的 BODY 中:简单地将您的 div 的类设置为“预加载”并将其样式属性设置为它应该正常加载的背景图像。像这样:

<div id="facials" class="preload" style="background: #ebebeb url('http://lamininbeauty.co.za/images/products/facial.jpg') no-repeat top right;">Facials Content</div>

那很容易吧?
然后将以下脚本放在 HTML 的 HEAD(这很重要)中:

// getElementsByClass original by dustin diaz, modified by GitaarLAB
document.getElementsByClassName=document.getElementsByClassName||function(searchClass,node,tag) {
    var classElements = [], i=0, j=0;
    if (!node){node = document;}
    if (!tag){tag = '*';}
    var els = node.getElementsByTagName(tag);
    var elsLen = els.length;
    var pattern = new RegExp('(^|\\\\s)'+searchClass+'(\\\\s|$)');
    for (; i < elsLen; i++) {
        if ( pattern.test(els[i].className) ) {
            classElements[j] = els[i]; j++;}
    } return classElements;
};

var repBg=(function(n,u,p,a,i,r){ // by GitaarLAB
    window.onload=function(){repBg(1);};
    i=new Image(); i.onload=function(){this.onload=null; repBg(2);};
    document.write("<style>."+n+"{background:"+p+" url("+u+") "+a+
        " !important; background-size: contain !important;}"+
        "</style>");
    i.src=u; r=0;
    return function(t){
        r=r+t; if(r>2){
            var c=document.getElementsByClassName(n), i=0, l=c.length, s;
            repBg.exec=function(){
                document.getElementById(this['data-id']).className='';
            };
            for(;i<l;i++){
                r=new Image();
                r.onload=repBg.exec;
                r['data-id']=c[i].getAttribute('id');
                s=c[i].getAttribute('style');
                try { // sane browsers
                    r.src=s.match(/url\('?([^'"]*)'?\)/i)[1];
                } catch(e) { // <IE8
                    r.src=s.cssText.match(/url\('?([^'"]*)'?\)/i)[1];
                }
            }
        }
    };
})('preload','http://lamininbeauty.co.za/images/products/loader.gif','#ebebeb','no-repeat top right');

说明:
我花了一整夜……但我找到了办法。
如果启用了 javascript,函数 repBg 将首先向文档头部写入一个额外的样式块(它所在的位置,注意将其放在最后一个 css 脚本之后),为所有元素设置 loader-background-image类“预加载”(从而在页面加载时显示加载图像)。
如果加载了加载图像的加载测试图像并且加载了窗口(以获取正文中的所有元素),那么它与版本 1 基本相同。只是这次我们从元素的样式属性和 onload 随后清空元素的样式属性。

由于此函数会自动执行并用类似于版本 1 的版本(如上)覆盖自身,因此您可以简单地在函数“repBg”的最后一行调整参数。
请注意:在初始状态repBg下,最多接受 4 个参数:className、Url、cssPrepend 和 cssAppend。

要查看它的实际效果(不要忘记按照说明清理浏览器缓冲区),
请单击此小提琴:http://jsfiddle.net/epdDa/1/

谁使用此功能,如果您感谢我,我将不胜感激!


更新:
评论的额外解释和答案。

两个版本之间的主要区别 从
技术上讲,两个版本使用几乎相同的技术,因此没有真正的区别。

  • 对于版本 1,javascript 是使页面工作所需的粘合剂,但可以在有效的真正 xhtml 和纯 html 中工作。
    但是,关闭 javascript 的人将获得一个无法正常工作的站点(仅显示加载 gif)。请注意,所有其他当前答案,包括您要去的方向,都会遇到这个问题!
  • 在版本 2 中,javascript 只是增强页面交互(网站应编码的方式)的香料,但仅适用于 html(或无效的 xhtml)。
    但是,这应该确保关闭 javascript 的人仍然可以看到正常运行的页面。IE: 不需要 javascript正确显示网站。这个概念被称为“优雅的后备”或“优雅地降级”。我对版本 2 投了第 1 票。
    额外奖励:这条路径为您提供了普通的验证和语义 html,因为您使用了古老的可信赖的内联样式、id 和类。我对第 2 版的第 2 票

为什么我选择使用 in-line css?为什么“必须”使用内联 CSS 才能正常工作?
首先,我花了几个小时来避免使用内联 CSS。(我没有松开它们,我学到了不起作用的方法,但同样有用)。接下来,我想再次指出,所有当前的答案,包括你要去的方向,实际的背景图像 url 与 css 分开,而在 css 中,你分别在每个 div 上设置加载器图像,一个类会更有意义。版本 2 仅使用可配置的类名。

在文档的 HEAD 中读取写入css 块都是一团糟。
我是否提到了链接的外部 css 文件..??

在我看来,所有这些都需要大量额外的代码和 cpu 周期,并在每次页面加载时阻止/停止浏览器,以便核心原则起作用:最后一个有效的 css 规则适用。因此加载图像会尽快显示,因为它是页面加载时指定的背景图像,这正是人们想要从这样的功能中获得的。如果元素不再是“预加载”类的一部分?对:它的内联 css 生效,以浏览器可以渲染的速度更新(如果图像已经加载)。好的。

因此,如果您通过简单地使用来牺牲(真正的)xhtml 支持document.write,那么目前仍然证明这种方式是“最好的”方式(正如您可以在前面的 2 个链接中阅读的那样)。并且它仍然可以与外部链接的 css 一起使用。我对第 2 版的第三次(KISS-)投票。

我对版本 2 的第四次投票是因为:该repBg函数已准备好将其exec方法(=函数)“升级”,因此您只能从类的 valuelist 中取出“preload”值。一个简单的 replace() 就足够了(目前为了速度而忽略了)。

我对版本 2 的第五次也是最后一次投票是,由于它是优雅的后备设置,因此修复或阻止某些浏览器使用额外的“香料”也相对容易。

最后,至于速度:我认为版本 2 总是会感觉更快捷:onload-image 的显示速度几乎与浏览器获取它的速度一样快(好像这个额外的 css 总是在那里一样),加载动画加载速度很快,因为:它们的加载已经在头部启动,浏览器在函数调用之前不会下载被否决的图像。此外,它们看起来互动而不会分心。但是..当实际的背景图像被加载并且css更新时:bam!图像在那里,没有从上到下的扫描“效果”。这种效果感觉该死的快。实际上,我确信并将对相册中的图像进行改编,以适应快速感觉和增加感知的初始页面加载。请注意,这是我的观点。你的里程可能会有所不同哈哈。

祝你好运!!(如果你喜欢/使用这个想法/功能,请投票,谢谢!!)

于 2012-08-11T20:28:19.307 回答
2

1)div元素没有load事件,该事件仅适用于正文、图像和脚本标签。编辑:就像@icktoofay 指出的那样,在 HTML 规范中onload,所有元素都存在,但是主要浏览器不支持这一点(目前)。

2) 将此脚本标记放在 html 页面的末尾

<script>
    function loadImages() {
        var glykopeels = document.getElementById('glykopeels');
        var facials = document.getElementById('facials');

         glykopeels.style.backgroundImage = 'url(http://lamininbeauty.co.za/images/products/glykopeel.jpg)';
         facials.style.backgroundImage = 'url(http://lamininbeauty.co.za/images/products/facial.jpg)';

​​​

3)你可以style.background像你做的那样设置,但不要把;字符串放在末尾,否则不起作用。

小提琴:http: //jsfiddle.net/pjyH9/

编辑

似乎加载器图像没有显示,因为一旦浏览器接收到新图像的第一个字节,它就会从背景中删除 loader.gif。让我们采取另一种方法。这是一个将图像加载到缓存的函数,然后 - 当加载图像时 - 将图像设置为具有指定 id 的元素的背景。

function loadImageToBackground(elementId, imageUri) {
    var img = new Image();
    img.onload = function() {
       document.getElementById(elementId).style.backgroundImage = "url('" + imageUri +   "')";
    };
    img.src = imageUri;   
}

你想要加载器的元素:

// past the element id and the image url to the function
loadImageToBackground('glykopeels', ​'http://image....');

我很确定这会奏效。该功能loadImageToBackground完成基本工作,您可以根据需要扩展和添加更多功能。

这是一个工作示例: http: //jsfiddle.net/pjyH9/19/ (它加载了 2 个图像,每个图像 1.5mb,因此您可以看到加载器的运行情况)。

于 2012-08-11T15:41:51.207 回答
1

我认为您要做的是让背景图像在加载后切换到大 JPG 图像。你应该能够适应这样的东西来为你工作:

<html>
  <head>
    <title>Image Load Test</title>
    <script type="text/javascript">
      function loadImage(preloader, imageDiv) {
        document.getElementById(imageDiv).style.background = '#ebebeb url('+preloader.src+') no-repeat top right';
        // I think resetting the background property also resets backgroundSize.
        // If you still want it 'contained' then you need to set the property again.
        document.getElementById(imageDiv).style.backgroundSize = 'contain';
      }
    </script>
    <style type="text/css">
      #testImage {
              background: #ebebeb url(small-image.gif) no-repeat top right;
              background-size: contain;
      }
      #preloads { display: none; }
    </style>
  </head>
  <body>
    <div id="testImage">Some Content</div>
    <div id="preloads">
      <img src="full-image.jpg" onload="loadImage(this, 'testImage')">
    </div>
  </body>
</html>

这里的主要区别是我将 JPG 图像预加载到<img>隐藏在 a<div>中的display: none属性中以使其隐藏。我不确定该onLoad事件对divs 的确切作用,但我很确定这不是您想要的。将onLoad事件放入img元素中会导致事件在图像完全加载后触发,我相信这就是您想要的。

编辑:我在 JavaScript 中添加了一行来重置background-size属性。如果那不是您想要的,那么请忽略该部分。

于 2012-08-11T15:41:14.373 回答