自动 HTML 预加载器

发布于 2024-09-09 03:00:39 字数 308 浏览 3 评论 0原文

我有一个页面,将使用 ajax 加载 HTML 块。所有这些片段都将具有图像,其中一些将使用背景图像在单独的 CSS 中指定。我想写一个预加载器,这样加载的块只有在所有加载完成后才会显示。如果所有图像都在 HTML 块中,我会加载它,将其放入隐藏元素中,然后查找所有 img 标签并控制它们是否已加载(或在 load 方法中放置一些回调)。问题是 CSS 我不能那么容易地做到这一点...所以我想到的唯一方法是拥有一个包含所有图像位置的单独的 xml 文件,并使用它来创建 IMG 元素,加载它们,并在它们被加载时加载它们。已加载显示块(因此图像已从服务器中提取)。您知道更好的方法吗?有现成的组件吗?

I've an page that will load chunks of HTML using ajax. All those fragments will have images and some of them will be specified in a separate CSS using background-image. I wanted to write a pre-loader, so that the loaded chunk will show up only when all the loading is complete. If all the images would have been in the HTML chunk, I would load it, put it in a hidden element, then look for all the img tags and control if they are loaded (or put some callbacks in the load method). The problem is CSS I can't do that so easily... So the only way that comes to my mind is to have a separate xml file with all the image locations and use it to create IMG elements, load them and when they are loaded display the chunk (so the images have already been pulled from the server). Do you know better approaches? Are there any ready components?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深府石板幽径 2024-09-16 03:00:40

如果你接受了一条建议,就不要这样做。这里优先考虑的是内容,图像是次要的。不要因为图像而让用户等待内容。这将是一件令人痛苦的事情,尤其是在连接速度较慢的情况下。

您最好使用一些占位符/指示符图像来提供有关加载组件的反馈,并且可能对 标记中的图像使用一些漂亮的淡入淡出效果。

注意:对于小图像,您可以尝试 数据:URI,允许您将图像嵌入到 HTML 或 CSS 文件中。


已更新

永远不要说不。 :) 这是您可以使用的原型。它在 FF 3+​​ 和 IE 5.5+ 中工作正常,但由于某种原因 Chrome 显示 cssRules 为空。我必须弄清楚为什么。另一个 TODO 是在 IE 中合并 @import-ed 规则,因为它不与标准规则集一起使用。

无论如何,正如您所看到的,您需要向其传递一个文档、一个回调,并且有一个可选超时参数(默认为 10 秒)。

回调将在文档中加载每个图像后执行。 (请注意,如果失败并返回 404,脚本将处理它)。在这里您可以进行淡入或显示或其他操作。

超时是作为后备措施,如果出现任何问题,它会在一定时间后调用回调。

// this function will execute a callback after all
// images has been loaded in a document
function imageLoader(document, callback, timeout) {

    timeout = timeout || 10000; // 10s default
    var i, j, remaining = 0;    // number of loading images
    // hash table to ensure uniqueness
    // url => image object
    var imgs = {};

    function handler(el, event) {
        remaining -= 1;
        if (remaining == 0 && !callback.done
         && typeof callback === "function") {
            callback.done = true;
            callback();
        }
    }

    // adds the image to the hash table
    function addImage(src, img) {
        if (!imgs[src]) {
          remaining++;
          img = img || new Image();
          img.onload  = handler;
          img.onerror = handler;
          img.src = img.src || src;
          // add to the hash table
          imgs[src] = img;
        }
    }

    // now gather all those images
    var sheets = document.styleSheets;
    for (i=0; i<sheets.length; i++) {

        // HTML <img> tags
        var els = document.getElementsByTagName("IMG");
        for (i=0; i<els.length; i++) {
            var el = els[i].src;
            addImage(el.src, el);
        }

        // CSS background images
        var css = sheets[i];
        var pos = css.href.lastIndexOf("/");
        var cssDir = (pos != -1) ? css.href.substring(0, pos + 1) : "";
        var rules  = css.cssRules || css.rules;

        for (j=0; j<rules.length; j++) {
            var style = rules[j].style;
            var img = style.backgroundImage;
            if (img == "none") img = "";
            var filename = img.substring(4, img.length - 1).replace(/['"]/g,"");
            if (filename) {
                if (filename.indexOf("http://") != 0
                 && filename.indexOf("/") != 0) {
                    filename = cssDir + filename;
                }
                addImage(filename);
            }
        }
    }

    // correct the start time
    var start = +new Date();

    var timer = setInterval(function(){
        var elapsed = +new Date() - start;
        // if timout reached and callback
        // hasn't been not called yet
        if (elapsed > timeout && !callback.done) {
            callback();
            callback.done = true;
            clearInterval(timer);
        }
    }, 50);
}

If you accept a piece of advice, don't do it this way. The priority here is the content, images are secondary. Don't let the user wait for the content, because of the images. It will be a pain in the ass, especially on slow connections.

Your best bet it to use some placeholder/indicator images to give feedback about the loading components, and maybe to use some nice fade in effect for images in <img> tags.

Note: for small images you can try Data: URIs, which allow you to embed images into HTML or CSS files.


UPDATED

Never say no. :) Here is a prototype of what you could use. It works fine for me in FF 3+, and IE 5.5+, but for some reason Chrome shows cssRules to be null. I have to figure out why. Another TODO is to merge @import-ed rules in IE as it doesn't serve then with the standard rule-set.

Anyways, as you can see you need to pass it a document, a callback and there is an optional timeout argument (10s by default).

The callback will be executed after every image is loaded in the document. (note if it fails with 404 the script will take care of it). Here you can do your fadeIn or show or somethin'.

The timeout is there as a fallback, if anything would go wrong, it calls the callback anyway after a certain amount of time.

// this function will execute a callback after all
// images has been loaded in a document
function imageLoader(document, callback, timeout) {

    timeout = timeout || 10000; // 10s default
    var i, j, remaining = 0;    // number of loading images
    // hash table to ensure uniqueness
    // url => image object
    var imgs = {};

    function handler(el, event) {
        remaining -= 1;
        if (remaining == 0 && !callback.done
         && typeof callback === "function") {
            callback.done = true;
            callback();
        }
    }

    // adds the image to the hash table
    function addImage(src, img) {
        if (!imgs[src]) {
          remaining++;
          img = img || new Image();
          img.onload  = handler;
          img.onerror = handler;
          img.src = img.src || src;
          // add to the hash table
          imgs[src] = img;
        }
    }

    // now gather all those images
    var sheets = document.styleSheets;
    for (i=0; i<sheets.length; i++) {

        // HTML <img> tags
        var els = document.getElementsByTagName("IMG");
        for (i=0; i<els.length; i++) {
            var el = els[i].src;
            addImage(el.src, el);
        }

        // CSS background images
        var css = sheets[i];
        var pos = css.href.lastIndexOf("/");
        var cssDir = (pos != -1) ? css.href.substring(0, pos + 1) : "";
        var rules  = css.cssRules || css.rules;

        for (j=0; j<rules.length; j++) {
            var style = rules[j].style;
            var img = style.backgroundImage;
            if (img == "none") img = "";
            var filename = img.substring(4, img.length - 1).replace(/['"]/g,"");
            if (filename) {
                if (filename.indexOf("http://") != 0
                 && filename.indexOf("/") != 0) {
                    filename = cssDir + filename;
                }
                addImage(filename);
            }
        }
    }

    // correct the start time
    var start = +new Date();

    var timer = setInterval(function(){
        var elapsed = +new Date() - start;
        // if timout reached and callback
        // hasn't been not called yet
        if (elapsed > timeout && !callback.done) {
            callback();
            callback.done = true;
            clearInterval(timer);
        }
    }, 50);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文