图片懒加载的几种方法

在一些图片比较多的网站会用到 图片懒加载 技术,这项技术可以延迟加载图像,只当图片出现在我们看到的视图中才加载,它的好处是大大提高用户体验,节省不必要的资源浪费以及网站的性能提升等。下面介绍几种图片懒加载的方法,分别是监听 scroll、resize 事件,使用 Intersection Observer API 以及 Chrome70 自带的懒加载设置。任何技术都是为解决问题服务的。在开始之前,还是要了解清楚「是什么」以及「为什么」。

什么是懒加载

当一个网站的图片数量较多时,直接加载可能会有很大的开销,不利于性能,这时可以将所有的图片换成轻量的占位图,不加载图片。而当用户真正滚动到图片出现时,再迅速将占位图片换成真正我们想展示的图片,这整个过程就是懒加载。

为什么要懒加载

当你打开一个网站时,浏览器会做许多工作,这其中包括下载各种可能用到的资源,然后渲染呈现在你面前,假设你的网站有大量的图片,那么加载的过程是很耗时的,尤其像那些新闻资讯类需要大量图片的网站,可想而知,网站的初始加载时间会很长,再加上网络等其它影响,用户体验会很差,相信你经常遇到过一个网站卡在某个地方,一直在加载,这种体验很不好。我们都希望一输入网址,页面立马就呈现在眼前。

既然想要页面立马呈现在面前,那势必要减少浏览器的负荷,优化代码,减少一些不必要的请求和不必要资源的加载,因为你打开网站的时候,浏览器会把所有可能的资源都下载好,而实际上有些资源你并不需要用到,这就造成了浪费。所以有必要在一些资源上做下优化,提高网站加载速度。

滚动事件监听

前面说到要等图片出现在视口时才加载,那么肯定要监控浏览器的 scroll 事件,并且要计算图片与浏览器窗口的距离来选择替换图片的 src 地址。代码如下:

HTML
<div>
  <img class="lazy-load" data-src="https://source.unsplash.com/random/600" alt="">
  <img class="lazy-load" data-src="https://source.unsplash.com/random/700" alt="">
  <img class="lazy-load" data-src="https://source.unsplash.com/random/800" alt="">
  <img class="lazy-load" data-src="https://source.unsplash.com/random/900" alt="">
</div>
// 引入 lodash 库
<script src="https://cdn.bootcss.com/lodash.js/4.17.12-pre/lodash.core.min.js"></script>  
CSS
div {
  margin-top: 350px;
}
.lazy-load {
  width: 200px;
  height: 150px;
}
JS
let lazyImages = [...document.querySelectorAll('.lazy-load')]
let inAdvance = 300
function lazyLoad() {
    lazyImages.forEach(image => {
        if (image.offsetTop < window.innerHeight + window.pageYOffset + inAdvance) {
            image.src = image.dataset.src;   // 替换真实图片的  URL
        }
    })
}
lazyLoad();
window.addEventListener('scroll', _.throttle(lazyLoad, 50))
window.addEventListener('resize', _.throttle(lazyLoad, 50))

这其中有几个属性,首先是 data-src,它是自定义属性,可以在 js 里通过 dataset 获得它的属性值;还有 offsetTop ,innerHeight 以及 pageYOffset 属性,你可以通过 MDN 文档查询他们的定义和用法;最后是 _.throttle 函数,它是一个节流函数,引用自 lodash 库,因为监听 scroll 滚动以及 resize 窗口改变事件会不断地触发,过于频繁,所以使用节流函数让其每隔一段时间执行,节省开销。

Intersection Observer API

现在,有一个 Intersection observer 接口可以方便我们操作,它可以异步观察目标元素与祖先元素或顶层文件的交集变化。简单的说,以前我们需要自己去写滚动监听事件函数,现在,这个 API 可以帮助我们,我们只需要统一写一个 观察函数 ,每当想观察的元素进入视口,也就是我们看见它时,就执行相应的操作。看看以下 js 代码:

<style>   // css 部分
  .lazy-load {
     width: 400px;
     height: 300px;
   }
</style>
<div>
    <img class="lazy-load" data-src="https://source.unsplash.com/random/600" alt="">
    <img class="lazy-load" data-src="https://source.unsplash.com/random/700" alt="">
    <img class="lazy-load" data-src="https://source.unsplash.com/random/800" alt="">
    <img class="lazy-load" data-src="https://source.unsplash.com/random/900" alt="">
</div>
document.addEventListener("DOMContentLoaded", function() {
    let lazyImages = [...document.querySelectorAll('.lazy-load')];
    if ("IntersectionObserver" in window) {
        // 创建一个观察函数,以便待会调用   
        let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
            entries.forEach(function(entry) {
            if (entry.isIntersecting) {
               let lazyImage = entry.target;
               lazyImage.src = lazyImage.dataset.src;   // 替换 src URL
               lazyImageObserver.unobserve(lazyImage);  // 解除观察
            }
            });
        });
        // 对所有需要懒加载的图片进行 “暗中观察”
        lazyImages.forEach(function(lazyImage) {
            lazyImageObserver.observe(lazyImage);
        });
     }else{
           alert('您的浏览器不支持 IntersectionObserver');
     }
});

可以看到,里面监听了 DOMContentLoaded 事件,当初始的 HTML 文档被完全加载和解析完成之后,这个事件就被触发,在页面初始之后获取到所有图片元素,然后进行观察。

那既然这个 API 这么好,又简便易用,有没什么缺点呢?相信你看了上面的代码就能知晓,对,浏览器兼容问题!!

can I use

可以看到,还是有很多泛红,只有 Chrome 支持的最好,从 58 以上版本就完全支持了,Firefox 也不错。如果你的项目不需要考虑兼容的话,可以尝试使用下它,看看效果。

Chrome 浏览器自带

这个方法厉害了,没有前面两种方法那么复杂,它是 Chrome 自带的原生 lazyload 属性,只需要一个开关。

chrome://flags/#enable-lazy-image-loading

复制它到 Chrome 浏览器的地址栏,然后找到如下选项,将其设置为「Enabled」。


image

然后在 HTML 标签里开启:

<img src="https://source.unsplash.com/random/600" alt="" lazyload="on">

不需要多余的代码,不需要 JS ,简直强大。

比较三者

秉承着尝试捣鼓新技术的原则,应该优先使用 Intersection Observer ,随着越来越多的浏览器支持会更广泛地应用;但如果要考虑浏览器的兼容问题,那就要使用平常的 scroll,resize 事件监听了,配合 offsetTop 、innerHeight 以及 pageYOffset 几个属性实现。至于最简单粗暴的那个方法,很明显只能在特定的 Chrome 70 以上版本中使用,有很大的局限性,不过现在使用 Chrome 的人非常的多,所以也是有用处的。
综合来看,应该将 Intersection Observerscroll,resize 结合起来使用,这可能是最优也最兼容的方案。

参考资料

[1] MDN 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API
[2] 延迟加载图像和视频:https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/
[3] Lazy load images:https://medium.com/@filipvitas/lazy-load-images-with-zero-javascript-2c5bcb691274

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 特别声明:此篇文章内容来源于@Jeremy Wagner的《Lazy Loading Images and Vid...
    Naeco阅读 30,666评论 0 32
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,450评论 1 45
  • 第一日 与你说星稀月朗 与你诗词共赏 你说桃李满村落 我说花事香了老街坊 第二日 彩虹出岫共天长 你说错过的光景下...
    敢问姑娘芳龄阅读 315评论 0 0
  • 苏小今阅读 136评论 0 0
  • 我还在探索黑暗中的隐秘 把新大陆说给星星听 月光时常都很朦胧 就像我和世界的距离 有人说 可以为孤独加冕 但我并不...
    云中飘舞阅读 2,137评论 57 74