懒加载与节流

2019-08-24  本文已影响0人  twentyshaw

1. 概念

懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式。 用户滚动到它们之前,可视区域外的图像不会加载。 这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。 在某些情况下,它还可以帮助减少服务器负载。

2. 对图片的配置

将图片的地址写在 data-src里,而不是src里面,方便我们操作它。并且为图片添加class名“lazyload”,标记出需要懒加载的图片。

3. 思路

监听页面的滚动(scroll事件),当页面滚动时遍历图片,判断图片是否在视口内,如果是就加载图片。

4. 代码

4.1. 监听浏览器的scroll事件:

window.addEventListener("scroll",onscroll)

4.2. 判断img是否处于视口:

4.3. 加载img

4.4. 节流

但此时虽然实现了懒加载,但以上的判断和加载会在滚动的时候不断重复调用。为了避免这种情况发生,需要节流:


5. 完整代码

function lazyload(images) {
  //将获取到的图片转成数组,也可以写成: Array.from(images)
  let imgs = [].slice.call(images || document.querySelectorAll('.lazyload'))  
  let onscroll = throttle(function() {
      if (imgs.length === 0) {
        return window.removeEventListener('scroll', onscroll)
      }
      imgs = imgs.filter(img => img.classList.contains('lazyload'))
      imgs.forEach(img => inViewport(img) && loadImage(img))
    }, 300)
  
  window.addEventListener('scroll', onscroll)
  window.dispatchEvent(new Event('scroll'))
}

function inViewport(img){
    let {top, bottom, left, right} = img.getBoundingClientRect()
    let vpWidth = document.documentElement.clientWidth
    let vpHeight = document.documentElement.clientHeight
    return (
        (top > 0 && top < vpHeight || bottom > 0 && bottom < vpHeight) &&
        (left > 0 && left < vpWidth || right > 0 && right < vpWidth)
    )
}

function loadImage(img, callback){
    let image = new Image() 
    image.src = img.dataset.src
    image.onload = function(){
        img.src = image.src
        img.classList.remove("lazyload")
        if (typeof callback === "function") callback()
    }
}

function throttle(func, wait){
    let prev,timer
    return function fn(){
        let curr = Date.now()
        let differ = curr - prev
        if (!prev || differ >= wait) {
            func()
            prev = curr
        }else if(differ < wait){
            clearTimeout(timer)
            timer = setTimeout(func, wait -differ)
        }
    }
}

6. IntersectionObserver接口

对图片的是否进入视口的观测(第4.2步),也可以通过IntersectionObserver API来实现:

   let observer = new IntersectionObserver(function(entries) {
      entries.forEach(entry => {
        if (entry.intersectionRatio > 0) {
          loadImage(entry.target, () => {
            observer.unobserve(entry.target)
          })
        }
      })
    }, { threshold: 0.01 })
  
    imgs.forEach(img => observer.observe(img))

上一篇下一篇

猜你喜欢

热点阅读