图片懒加载的方案

前言

图片懒加载是前端性能提升的重要方面之一,其主要的用途是: 减少网络加载,提升体验。

但为了影响体验,你需要最好写好布局样式,最好写好占位图。

懒加载的原理

其实图片的加载主要是因为图片的src引起的,而如果我们想要实现懒加载,就避免src路径的加载即可,我们可以将图片的路径存储到data-src的自定义数据属性上,然后在需要的时候按需加载。

按需加载的实现方式有两种:这里重点说第一种,目前在移动端以及在pc的瀑布流布局中都是第一种居多。
1 滚动到页面底部加载
2 分页加载

滚动到页面底部加载的原理

原来的方式:滚动监听

其主要实现的原理是对滚动事件的监听,当发现滚动条高度+滚动条高度等于document的高度时,就是达到页面的底部了,需要重新加载图片的时机。

$(window).scroll(function(){
 if($(window).scrollTop() +$(window).height()>=$(document).height()){
   var $div = '<li>append添加的节点</li>';
		$('#container').append($div)
 }
});

新的方式:IntersectionObserver

我们去看下jq的lazyload的源码是如何写这部分函数的,核心是依赖IntersectionObserver,是检测元素是否进入视图,如果有进入,那么就会移除其lazy的class,其源码地址:链接

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  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;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to a more compatible method here
  }
});

如何实现图片懒加载

概念

图片懒加载是针对图片加载时机的一种优化,在一些图片量比较大的网站(比如电商网站首页,或者团购网站、小游戏首页等),如果我们尝试在用户打开页面的时候,就把所有的图片资源加载完毕,那么很可能会造成白屏、卡顿等现象,因为图片真的太多了,一口气处理这么多任务,浏览器做不到啊!

懒加载是为了让浏览器只加载可视区内的图片,可视区外的大量图片不进行加载,当页面滚动到后面去的时候再进行加载。这样做有很多好处可以增加首屏加载的速度,毕竟,用户点开页面的瞬间,呈现给他的只是首屏,我们只要把首屏的资源图片加载处理就可以了,至于下面的图片,当用户下滑当当前位置的时候,在加载出来也是没问题的,对于性能压力也小了,用户体验也没有变差。

解答

图片懒加载的原理就是需要知道图片是否在可视区内了,当图片到达可视区内就需要去请求对应的图片加载出来

页面中的img标签一般如下写

<img class="lazyload" src="placeholder.jpg" data-src="real_image.jpg" /> 

其中src首先赋值一个占位的图片,一般是一个很小的图片,进行占位,data-src是实际需要展示的图片,原理就是当图片在可视区内的时候将data-src的图片选渲染出来即可。

实现

1、原生实现

Chrome 76 将原生支持图片的惰性加载,支持对img和iframe进行延迟加载,只需要将loading属性设置为lazy即可。

<img src="celebration.jpg" loading="lazy" alt="..." /> <iframe src="video-player.html" loading="lazy"></iframe> 

原生实现的好处是,不需要任何脚本,纯原生HTML即可,简单方便,支持多种属性

  • lazy:对资源进行延迟加载。
  • eager:立即加载资源。
  • auto:浏览器自行判断决定是否延迟加载资源。

原生的坏处就是在于浏览器的支持率不是很高,将来肯定是非常好的。

2、Element.getBoundingClientRect()

getBoundingClientRect返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合, 即:是与该元素相关的CSS 边框集合 。DOMRect 对象包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。有了这个API后我们很同意获取图片的top值,当top值小于可视区的高度的时候就可以任何图片进入了可视区,直接加载图片即可

element.getBoundingClientRect().top < document.documentElement.clientHeight

由于需要在滚动的时候去监听图片的位置,所以我们需要使用到window.onscroll事件,我们在事件内部处理相关的逻辑即可。

3、通过相对计算获取元素位置
  1. 通过document.documentElement.clientHeight获取屏幕可视窗口高度。
  2. 通过element.offsetTop获取元素相对于文档顶部的距离。
  3. 通过document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离。 然后判断2-3<1是否成立,如果成立,元素就在可视区域内。
element.offsetTop -  document.documentElement.scrollTop < document.documentElement.clientHeight

此方法也需要在滚动的时候去监听图片的位置,所以我们需要使用到window.onscroll事件,我们在事件内部处理相关的逻辑即可。

4、使用IntersectionObserver
const observer = new IntersectionObserver(callback, observerConfig)

const imgList = document.querySelectorAll(".lazyload");
const observer = new IntersectionObserver(entries => {
    entries.forEach(item => {
        if (item.isIntersecting) {
            item.target.src = item.target.dataset.origin; // 判断在可视区了,把data-origin的值放到src
            observer.unobserve(item.target); // 已经加载过的图片停止进行监听
        }
    });
});
imgList.forEach(item => observer.observe(item));

补充

1、优化

由于上面某些情况是需要使用到window.scroll事件的,所以我们可以增加节流来减少事件处理函数的调用次数。 假设我们判断是否可视区逻辑为函数loadImage那么我们可以如下处理。

window.onscroll = throttle(loadImage, 500)

2、拓展

上面后续三种方法不仅仅可以使用在图片的懒加载上面,其实所有可以懒加载的地方都可以通过这种方式进行判断,比如列表分页加载,我们可以通过这种方式进行判断是否需要进行下一页的加载,比如我们需要埋曝光埋点的时候,可以通过这种方法判断元素是否曝光,进行埋点事件的触发。
 

推荐文章

vue3-lazyload使用

"vue3-lazyload": "^0.3.6"

import VueLazyload from 'vue3-lazyload'

app.use(VueLazyload, {
  loading: 'loading/loading.png',
  error: 'loading/default.jpg'
})

// 页面使用
<img v-lazy="" />

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值