js实现图片懒加载的一个详细方案(引入即可使用)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>懒加载</title>
  <style>
    img {
      
      
      width: 600px;
      height: 450px;
    }
  </style>
  <script src="./lazyLoad.js"></script>
</head>
<body>
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
  <img src="" data-src="./imgs/css3.png">
</body>
</html>

lazyLoad.js

/**
 * 在使用一下懒加载的方式之前,图片要设置宽高,不设置宽高,会判断所有图片都在可视区域内
 * 整个懒加载方案还需要一下几点的优化:
 * 1. 可视区域的的元素,目前是浏览器可视窗口,无法对可视区域进行判断
 * 2. 事件监听一直存在,目前没有做销毁,考虑在图片全部加载完成后,销毁会导致后续增加的图片就无法触发懒加载
 * 3. 对于元素的选中,虽然是通过标签名+属性值,但后续还可进行优化,从而获取更加精准的懒加载目标
 */
window.onload = function() {
    
    
  var imgList = []
  var leftInterval = 100 * window.devicePixelRatio // 横向阈值
  var heightInterval = 200 * window.devicePixelRatio // 纵向阈值
  var throttleTime = 1000 // 节流时间
  var debounceTime = 1000 // 防抖时间
  var errorSrc = './imgs/wallhaven-1jxw53.jpg' // 图片加载失败的图片

  // 判断图片是否出现出现在可视区域的首选方案
  var observer = new IntersectionObserver(function(entries) {
    
    
    entries.forEach(item => {
    
    
      if (item.isIntersecting) {
    
    
        // 只处理src=""和没有src属性的图片
        if (item.target.src !== null) {
    
    
          handleImgSrc(item.target)
          observer.unobserve(item.target)
        }
      }
    })
  })

  // 给图片添加src,并处理onerror事件
  function handleImgSrc(dom) {
    
    
    // 已经显示的图片不再处理
    if (dom.getAttribute('src')) return
    const dataSrc = dom.getAttribute('data-src')
    if (dataSrc) {
    
    
      dom.src = dataSrc
    }
    dom.onerror = () => {
    
    
      dom.src = errorSrc
    }
  }

  // 节流函数
  function throttle(callback, delay) {
    
    
    let timer = null
    let _this = this
    return function(...args) {
    
    
      if (!timer) {
    
    
        timer = setTimeout(() => {
    
    
          callback.call(_this, args)
          timer = null
        }, delay)
      }
    }
  }

  // 防抖函数
  function debounce(callback, delay) {
    
    
    let timer = null
    let _this = this
    return function(...args) {
    
    
      clearTimeout(timer)
      timer = setTimeout(() => {
    
    
        callback.call(_this, args)
      }, delay)
    }
  }

  // 判断图片是否出现再可是区域额兼容性写法
  function isIn(dom) {
    
    
    const clientWidth = window.innerWidth,
          clienHeight = window.innerHeight,
          bound = dom.getBoundingClientRect()
    return (bound.top < clienHeight + heightInterval && bound.left < clientWidth + leftInterval)
  }


  // 懒加载
  function lazyLoad() {
    
    
    imgList.forEach(item => {
    
    
      if (IntersectionObserver) {
    
    
        observer.observe(item)
      } else if (isIn(item)) {
    
    
        handleImgSrc(item)
      }
    })
  }

  // 根据标签name和属性,获取相应的dom
  function getElementsByTagNameAndAttribute(tag, attribute) {
    
    
    const allTags = document.getElementsByTagName(tag)
    return Array.from(allTags).filter(item => {
    
    
      return item.getAttribute(attribute)
    })
  }

  // 这里用一个变量记录,后期优化可以方便清除监听,
  // 目前没有设置清楚监听,考虑第一轮图片加载完后,将监听清除后,后面第二轮的图片就无法实现懒加载的功能
  var throttleLazy = throttle(lazyLoad, 1000)
  var debounceLazy = debounce(lazyLoad, 1000)

  function init() {
    
    
    imgList = getElementsByTagNameAndAttribute('img', 'data-src')
    lazyLoad()
    window.addEventListener('scroll', throttleLazy, throttleTime)
    window.addEventListener('resize', debounceLazy, debounceTime)
  }

  init()
}

猜你喜欢

转载自blog.csdn.net/Wind_AN/article/details/125024429
今日推荐