以前写过一篇文章:【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); }
网友评论文明上网理性发言 已有1人参与
发表评论:
评论列表