项目中的懒加载——随手小记

图片懒加载在一些图片密集型的网站中运用比较多,通过图片懒加载可以让一些不可视的图片不去加载,避免一次性加载过多的图片导致请求阻塞(浏览器一般对同一域名下的并发请求的连接数有限制),这样就可以提高网站的加载速度,提高用户体验。
在做项目时我们需要让我们html中需要懒加载的img标签的src不设置,然后自定义一个属性,值为真正的图片或者原图的地址(比如下面的data-src),并且我们定义一个类名,表示该图片是需要懒加载的(比如下面例子的lazy-image),这有两个作用: 1、为以后获取需要懒加载图片的img元素 2、可以给这个类名设置背景图片,作为图片未加载前的过度图片,比如显示为loading的图片。
在检测图片是否出现在浏览器的可视区域时,我们有两种办法:
1.利用滚动事件 scroll 监听窗口元素,页面加载时判断图片的offsetTop是否出现在浏览器的可视区域,为true 时把img标签data-src属性赋值给src,这样就达到了图片懒加载需求。
2.使用 Intersection Observer
Intersection Observer API提供了一种异步观察目标元素与祖先元素或顶级文档viewport的交集中的变化的方法。
聊聊不熟悉的Intersection Observer懒加载。

<img class="lazy-image" data-src="images/1.jpg"/>
//css
.lazy-image {
    background: url('../images/loading.gif') no-repeat center;
  }
  
  img{
    margin-top: 100px;
    background-size: cover;
    background-position: center;
    width: 490px;
    height: 242px;
  }

在页面加载完后,我们需要获取所有需要懒加载的图片的元素集合,把懒记载图片列表中将伪数组转为数组,以便可以使用数组的api
同时判断图片是否在可视区域,如果是在可视区域的话,把自定义元素data-src转换为src,属性值为真正图片的地址。这里判断是否出现在可视区域内,是通过获取元素的getBoundingClientRect属性的top值和页面的clientHeight进行对比,如果top值小于clientHeight,则说明元素出现在可视区域了。
当图片不在可视区时移除掉已经显示的图片。
如下:

class LazyImage {
    constructor(selector) {
      // 懒记载图片列表,将伪数组转为数组,以便可以使用数组的api
      this.lazyImages = Array.prototype.slice.call(document.querySelectorAll(selector))
      this.init()
    }
  
    init() {
      // 通过IntersectionObserver api判断图片是否出现在可视区域内,不需要监听Scroll来判断
      if ("IntersectionObserver" in window) {
        let lazyImageObserver = new IntersectionObserver((entries, observer) => {
          entries.forEach((entry, index) => {
            // 如果元素可见
            if (entry.isIntersecting) {
              let lazyImage = entry.target
              lazyImage.src = lazyImage.dataset.src
              lazyImageObserver.unobserve(lazyImage)
              // this.lazyImages.splice(index, 1)
            }
          })
        })
        this.lazyImages.forEach(function(lazyImage) {
          lazyImageObserver.observe(lazyImage);
        })
      } else {
        this.inViewShow()
        this._throttleFn = this.throttle(this.inViewShow)
        document.addEventListener('scroll', this._throttleFn)
      }
      inViewShow() {
      // 不支持IntersectionObserver api的情况下判断图片是否出现在可视区域内
      let len = this.lazyImages.length
      for(let i = 0; i < len; i++) {
        let lazyImage = this.lazyImages[i]
        const rect = lazyImage.getBoundingClientRect()
        // 出现在视野的时候加载图片
        if(rect.top < document.documentElement.clientHeight) {
          lazyImage.src = lazyImage.dataset.src
          // 移除掉已经显示的
          this.lazyImages.splice(i, 1)
          len--
          i--
          if(this.lazyImages.length === 0) {
            // 如果全部都加载完 则去掉滚动事件监听
            document.removeEventListener('scroll', this._throttleFn)
          }
        }
      }
    }
  
    throttle(fn, delay = 15, mustRun = 30) {
      let t_start = null
      let timer = null
      let context = this
      return function() {
        let t_current = +(new Date())
        let args = Array.prototype.slice.call(arguments)
        clearTimeout(timer)
        if(!t_start) {
          t_start = t_current
        }
        if(t_current - t_start > mustRun) {
          fn.apply(context, args)
          t_start = t_current
        } else {
          timer = setTimeout(() => {
            fn.apply(context, args)
          }, delay)
        }
      }
    }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值