×

关于移动端懒加载lazyload应用的优化

作者:Terry2016.02.19来源:Web前端之家浏览:36388评论:1
关键词:lazyload

pc-b107dc52-2db4-11e4-954d-000c29f61318.png

以前写过一篇文章:【jQuery插件】图片延迟加载之jQuery.lazyload,介绍了lazyload的用法和技巧,今天主要探讨在移动端应用的优化。

可视区的计算

    通过对window绑定scroll事件,获取被隐藏在可视区域上方的像素数, 再计算img纵向偏移量。当被隐藏在可视区域上方的像素数大于img纵向偏移量+可视区高度时替换img的src。

    很多时候业务需要让页面初始化的时候就定位到页面某个位置,前面那样简单的判断会对页头至定位目标位置之间img浪费加载。可以通过getBoundingClientRect()方法获取img相对于视口的位置,从而判断是否需要加载目标图片。

var eLvW, elvH,
var inViewTreshhold = 10;
 
//...
//inViewTreshhold值可以根据页面是否加载完动态改变大小,当页面加载完的时候增大,也可说页面负担小的时候预加载多一些
 
eLvW = window.innerWidth + inViewTreshhold;
elvH = window.innerHeight + inViewTre·shhold;
eLnegativeTreshhold = inViewTreshhold * -1;
rect = lazyloadElems[globalLazyIndex].getBoundingClientRect();
 
//判断是否在可视区域
if ((eLbottom = rect.bottom) >= eLnegativeTreshhold &&
    (eLtop = rect.top) <= elvH &&
    (eLright = rect.right) >= eLnegativeTreshhold &&
    (eLleft = rect.left) <= eLvW &&
    (eLbottom || eLright || eLleft || eLtop)) {
    //执行加载图片动作
    //...
}

事件节流

scroll、touchmove、resize事件会触发大量的计算,在低版本Andorid版本浏览器中卡顿甚至崩溃,我们可以简单做一些事件节流的操作。

var eLnow = Date.now();
var lazyEvalLazy = (function() {
    var timer, running;
    var unblock = function() {
        running = false;
    };
    var run = function() {
        clearTimeout(timer);
        //执行加载图片动作
        //...
        setTimeout(unblock);
    };
    return {
        debounce: function() {
            clearTimeout(timer);
            running = true;
            timer = setTimeout(run, 66);
        },
        throttled: function() {
            var delay;
            if (!running) {
                running = true;
                clearTimeout(timer);
                delay = Date.now() - eLnow;
                if (delay > 300) {
                    delay = 9;
                } else {
                    delay = 99;
                }
                timer = setTimeout(run, delay);
            }
        }
    };
})();

lazyEvalLazy.debounce用来优化resize事件。lazyEvalLazy.throttled用来优化scroll、touchmove等事件,避免频繁触发。

响应式图片

一般响应式图片解决方案:

img {
    max-width: 100%;
    height: auto;
}

现在<picture>元素好像很有用。假如你的chrome版本是38+,在新标签页打开chrome://flags,勾选’启用实验性网络平台功能enable-experimental-web-platform-features,重启, 查看demo
目前浏览器对<picture>元素支持的不太好,可以做一些降级处理。

<picture>
    <source media="(min-width: 1000px)" srcset="http://img.qiang.it/1000x1000">
    <source media="(min-width: 500px)" srcset="http://img.qiang.it/500x500">
    <source srcset="http://img.qiang.it/100x100">
        <img data-sizes="auto" class="lazyload" data-src="http://img.qiang.it/100x100" data-srcset="http://img.qiang.it/240x240 240w,
    http://img.qiang.it/320x320 320w,
    http://img.qiang.it/480x480 480w,
    http://img.qiang.it/768x768 768w,
    http://img.qiang.it/1000x1000 1000w" alt="不支持picture的时候显示" />
</picture>

用例如window.HTMLPictureElement这样的方法来判断浏览器是是否支持<picture>,对不支持<picture>的元素引入respimage.js,或者直接内置到你lazyload组件里。

if(!window.HTMLPictureElement){
    console.log("no picture")
    //shiv picture element
    document.createElement('picture');
    //load respimage polyfill
    document.write('<script src="respimage.js"></script>');
}

如果全部以iphone为基准做高清图,那么90%以上的手机对服务器端的请求至少多出40%,对服务器和带宽都是巨量的消耗。在无wifi情况下,看的最多的就是菊花转和进度条,根本不能愉快的购物。也许可以这样做:

<img data-srcset="http://img.qiang.it/320x100 1x, http://img.qiang.it/640x200 2x" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==" class="lazyload" />

现在iphone6、iphone6S系列也有了一定的份额,屏幕越来越大,高清图加载越来越吃力。也许可以对这些设备做一些优化:

<img data-srcset="http://img.qiang.it/320x100 1x, http://img.qiang.it/640x200 2x" src="http://img.qiang.it/10x10" class="lazyload" />

先加载一个很小的图片,然后等待高清图像load完毕再替换一下src,这样就有了一个图像模糊到高清的过程,相比空白区域的等待也许会好一些。

事件的监听和触发

通常异步获取数据插入到页面的时候需要再次执行例如$(element).lazyload()这样的方法,这样不利于不了解这个组件的人使用。
我们可以检测window.MutationObserver事件或对document.documentElement绑定DOMAttrModified事件触发lazyload行为。

var element = document.body || document.documentElement;
//lazySizesConfig.mutation为配置选项
if (lazySizesConfig.mutation) {
    if (window.MutationObserver) {
        new MutationObserver(lazyEvalLazy.throttled).observe(document.documentElement, {
            childList: true,
            subtree: true,
            attributes: true
        });
    } else {
        element.addEventListener("DOMNodeInserted", lazyEvalLazy.throttled, true);
        document.documentElement.addEventListener("DOMAttrModified", lazyEvalLazy.throttled, true);
    }
}

其他事件的监听

//:hover
if (lazySizesConfig.hover) {
    document.addEventListener('mouseover', lazyEvalLazy.throttled, true);
}
//:focus/active
    document.addEventListener('focus', lazyEvalLazy.throttled, true);
//:target
    window.addEventListener('hashchange', lazyEvalLazy.throttled, true);
 
//:fullscreen
if (('onmozfullscreenchange' in element)) {
    window.addEventListener('mozfullscreenchange', lazyEvalLazy.throttled, true);
} else if (('onwebkitfullscreenchange' in element)) {
    window.addEventListener('webkitfullscreenchange', lazyEvalLazy.throttled, true);
} else {
    window.addEventListener('fullscreenchange', lazyEvalLazy.throttled, true);
}
 
if (lazySizesConfig.cssanimation) {
    document.addEventListener('animationstart', lazyEvalLazy.throttled, true);
        document.addEventListener('transitionstart', lazyEvalLazy.throttled, true);
}

源码参考:https://github.com/aFarkas/lazysizes

您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://jiangweishan.com/article/lazyload-youhua.html

网友评论文明上网理性发言 已有1人参与

发表评论:

评论列表