JavaScript 实现图片懒加载的三种常用方法

本文详细介绍了图片懒加载的概念、原因,以及三种常见的实现方式:基于元素位置的getBoundingClientRect、整体距离判断和IntersectionObserverAPI。通过这些方法,可以提升网页性能,减少资源消耗。
摘要由CSDN通过智能技术生成

1.1 什么是使用图片懒加载?

懒加载是一种对网页性能优化的方式,比如当访问一个网页的时候,优先显示可视区域的图片而不是一次加载全部的图片,当需要显示时,再发送请求加载图片。

1.2 为什么使用图片懒加载?

  1. 避免首次加载时消耗大量时间,降低页面渲染速度,造成卡顿现象。
  2. 按需加载,避免无效图片的加载,减轻服务器压力,节约网络资源。
  3. 若不使用图片懒加载,页面启动时,会加载全部的图片资源:

1.3 图片懒加载的实现原理

1 基本原理: 监听图片是否位于页面的可视区域内,若在则加载图片,不在则不加载图片

2 实现方案: 自定义属性-将图片真实地址 url 存储在自定义属性中,当监听到图片进入可视区域时,将自定义属性值赋值给 img 的 src 属性

实现方法

2.1 利用元素的 getBoundingClientRect 方法实现

(1)属性介绍:

利用.getBoundingClientRect实时获取物体的动态位置

(2)实现步骤:

步骤 1:监听页面滚动事件,lazyLoad为页面滚动时的处理函数,在本节为处理图片懒加载

window.addEventListener('scroll', lazyLoad)

步骤 2:判断图片是否处于可视区域内

(1)若距离顶部top小于页面的整体高度window.innerHeight

(2)若距离左侧left小于页面的整体宽度window.innerWidth

(3)同时图片的底部bottom与图片的右侧right 距页面顶部、左侧的距离均大于0

则说明该图在屏幕的可视区域内。

为了提高复用性,我们可以将它封装成一个自定义函数isVisible,将每张图片作为参数传入该函数,并返回truefalse

// 可视区域判断函数
  function isVisible(img) {
    // 判断是否在可视区域,并返回true或false
    const imgRect = img.getBoundingClientRect() // getBoundingClientRect 获取图片的动态信息
    return imgRect.bottom > 0 && imgRect.top < window.innerHeight && imgRect.right > 0 && imgRect.left < window.innerWidth
  }

步骤 3:定义图片懒加载时的处理事件,监听所有的img,判断该img是否处于可视范围内

querySelectorAll 获取的元素为伪数组 需要转为真数组,否则无法使用数组的某些方法

// 获取所有的img元素,并利用扩展运算符转为真数组
const images = [...document.querySelectorAll('img')] 

 

步骤 4:对每张图片进行监听,利用自定义函数isVisible判断是否在可视区域内

(1)若处于可视区域:将自定义的data-src值,赋值给真正的src属性值,其中 data-src存储图片的URL地址,并删除该元素防止重复加载

(2)若不处于可视区域:return 不做处理

// 利用循环判断每张图片是否属于可视区域
function lazyLoad(){
    for (let i = 0; i < images.length; i++) {
    // isVisible是否该图片位于可视区域 返回true 或false
      if (isVisible(images[i])) {
        // 将元素的自定义属性 data-src 赋值给元素的 src 属性
        // 等价于:img.setAttribute('src', img.getAttribute('data-src'))
        images[i].src = images[i].dataset.src 
        // 防止重复被遍历 加载完之后 删除元素不再加载
        images.splice(i, 1)
        i--
      }
    }
}
lazyLoad()

(3)整体代码:

  // html 标签结构
  <img data-src="./public/image/VCG211430870249.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211430987515.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211431054751.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211435102490.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438229829.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438109615.jpg" src="./public/image/默认.jpg" alt="">
// 1 获取全部图片的DOM节点
// 注意:querySelectorAll 值为伪数组利用扩展运算符转为真数组
const images = [...document.querySelectorAll('img')] 

// 2 监听页面滚动事件
window.addEventListener('scroll', lazyLoad)

// 3 定义页面滚动的处理函数
function lazyLoad(){
    for (let i = 0; i < images.length; i++) {
    // isVisible是否该图片位于可视区域 返回true 或false
      if (isVisible(images[i])) {
        // 将元素的自定义属性 data-src 赋值给元素的 src 属性 
        // dataset.src 此为元素的自定义属性 data-src
        images[i].src = images[i].dataset.src // 等价于:img.setAttribute('src', img.getAttribute('data-src'))
        // 防止重复被遍历 加载完之后 删除元素不再加载
        images.splice(i, 1)
        i--
      }
    }
}
lazyLoad()

// 4 可视区域判断函数
  function isVisible(img) {
    // 判断是否在可视区域
    const imgRect = img.getBoundingClientRect() // getBoundingClientRect 获取图片的动态信息
    return imgRect.bottom > 0 && imgRect.top < window.innerHeight && imgRect.right > 0 && imgRect.left < window.innerWidth
  }

2.2 利用整体距离实现

(1)属性介绍:

  • clientHeight : 网页可见区域高
    • A 表示可见区域的高度,包含padding 不包含 bordermargin
    • B 语法:element.clientHeight
    • C 备注:body.clientHeight = window.innerHeight
  • innertHeight : window 整体高度
    • A 表示window的内部高度,包括纵向滚动条
    • B 语法:window.innertHeight
  • offsetTop : 距离父级元素顶部的高度
    • A 表示当前元素相对于其offsetParent元素的顶部内边距的距离
    • B 语法:element.offsetTop
  • scrollTop : 网页被卷去的距离
    • A 表示在有滚动条时,滚动条向下滚动的距离也就是元素顶部被遮住部分的高度
    • B 语法:element.scrollTop

(2)实现步骤:

可以用image.offsetTop <= document.documentElement.clientHeight + document.documentElement.scrollTop 判断图片是否可以在可视区域内。

  • 图片元素位置的顶部距离:offsetTop

  • 滚动距离的最下端:scrollTop+clientHeight

  // html 标签结构
  <img data-src="./public/image/VCG211430870249.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211430987515.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211431054751.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211435102490.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438229829.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438109615.jpg" src="./public/image/默认.jpg" alt="">
// 1 获取全部图片的DOM节点
// 注意:querySelectorAll 值为伪数组利用扩展运算符转为真数组
const images = [...document.querySelectorAll('img')] 

// 2 监听页面滚动事件
window.addEventListener('scroll', lazyLoad)

// 3 定义页面滚动的处理函数
function lazyload(e){
  // 3.1 获取屏幕的可视高度
  const clientHeight = document.documentElement.clientHeight
  // 3.2 获取屏幕的滚动距离
  const scrollTop = document.documentElement.scrollTop
  for (let i = 0; i < images.length; i++) {
    if (images[i].offsetTop < clientHeight + scrollTop) {
      images[i].setAttribute('src', images[i].getAttribute('data-src'))
    }
  }
}

2.3 利用Intersection Observer实现

Intersection Observer是一个比较新的api,他允许你追踪目标元素与其祖先元素或视窗的交叉状态,用他来检测图片是否进入视口非常方便,不用再像之前绑定事件、计算距离等。

(1)属性介绍:

  • 利用Intersection Observer实例上的observeunobserve方法,注册或取消监听事件。

  • 利用isIntersecting方法,判断该图片是否处于图片与屏幕可视区域的交叉范围内。

  • 注意:Intersection Observer实例会监听交叉状态,即出现和消失(触发两次),出现交叉状态后会去调用new的时候传入的callback回调函数

(2)实现步骤:

步骤 1: 监听页面滚动事件,lazyLoad为页面滚动时的处理函数,在本节为处理图片懒加载。

window.addEventListener('scroll', lazyLoad)

步骤 2: 创建图片与可视区域交叉实例

callback

  • 此为传入的回调函数,用于当处于交叉状态改变时进行的处理函数
  • 该函数会被触发2次:图片进入视野时+图片离开视野时
 const observer = new IntersectionObserver(callback)

步骤 3: 利用observer实例上的.observe(img)方法,给每张图片绑定观察事件

// 给每一个图片绑定观察方法
  imagess.forEach(img => {
    // 图片进入视野+离开视野时会触发callback回调函数
    observer.observe(img)
  })

步骤 4: 定义图片的懒加载事件

imgArr:

  • 可以获得包含所有图片的isIntersecting属性的集合,该属性可判断是否在交叉区域内
  • target为该图片的标签元素

image.png

  // callback 接收的参数为带有监听所有图片交叉属性的集合
  const callback = (imgArr) => {
    console.log('视图交叉时触发,离开交叉时也触发', imgArr) 
    imgArr.forEach(e => {
      // 判断是否在视野区域
      if (e.isIntersecting) {
        e.target.src = e.target.dataset.src
        // 取消监听,避免重复加载同一张图片
        observer.unobserve(e.target)
      }
    })
  }

(3)整体代码:

  // html 标签结构
  <img data-src="./public/image/VCG211430870249.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211430987515.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211431054751.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211435102490.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438229829.jpg" src="./public/image/默认.jpg" alt="">
  <img data-src="./public/image/VCG211438109615.jpg" src="./public/image/默认.jpg" alt="">
  // intersectionObserver 交叉观察 : 目标元素和可视窗口会产生交叉区域
  const imagess = [...document.querySelectorAll('img')]

  // 2.1 创建视觉交叉的观察实例
  const observer = new IntersectionObserver(callback)
  // 2.2 给每一个图片绑定观察方法
  imagess.forEach(img => {
    // 2.3 图片进入视野+离开视野时触发 - 回调
    observer.observe(img)
  })

  // callback 接收的参数为带有监听所有图片交叉属性的集合
  const callback = (imgArr) => {
    console.log('视图交叉时触发,离开交叉时也触发', imgArr) // imgArr为
    imgArr.forEach(e => {
      // 判断是否在视野区域
      if (e.isIntersecting) {
        e.target.src = e.target.dataset.src
        // 取消观察追踪,避免重复加载同一张图片
        observer.unobserve(e.target)
      }
    })
  }

  • 44
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Lazyload 是一个常用图片懒加载库,它支持以下几种方法: 1. 使用 HTML 属性 在 img 标签中添加 "data-src" 属性,将需要加载的图片地址作为属性值,再添加 "class" 属性,设置为 "lazyload",如下所示: ```html <img class="lazyload" data-src="image.png" alt="Image"> ``` 2. 使用 JavaScript 先将需要懒加载的图片地址存储在一个数组中,再使用 JavaScript 获取所有需要懒加载的图片元素,将它们的 "src" 属性设置为一个占位符(如空白图片),再将 "data-src" 属性的值设置为需要加载的图片地址。 最后,在 window 对象的 "load" 和 "scroll" 事件中,判断图片是否进入可视区域,如果是,则将 "data-src" 属性的值赋给 "src" 属性,实现图片加载。 ```javascript // 存储需要懒加载的图片地址 const images = [ 'image1.png', 'image2.png', 'image3.png' ]; // 获取所有需要懒加载的图片元素 const lazyImages = document.querySelectorAll('.lazyload'); // 遍历所有图片元素,设置 src 属性为占位符,data-src 属性为需要加载的图片地址 lazyImages.forEach((lazyImage, index) => { lazyImage.src = 'placeholder.png'; lazyImage.dataset.src = images[index]; }); // 判断图片是否进入可视区域,如果是,则将 data-src 属性的值赋给 src 属性 function lazyLoad() { lazyImages.forEach(lazyImage => { const imageTop = lazyImage.getBoundingClientRect().top; if (imageTop < window.innerHeight) { lazyImage.src = lazyImage.dataset.src; lazyImage.classList.remove('lazyload'); } }); } // 监听 window 对象的 load 和 scroll 事件,执行懒加载 window.addEventListener('load', lazyLoad); window.addEventListener('scroll', lazyLoad); ``` 3. 使用 IntersectionObserver API IntersectionObserver 是一个 Web API,它可以监测元素是否进入可视区域,可以用于图片懒加载。 首先,创建一个 IntersectionObserver 实例,设置回调函数,当被观察的元素进入可视区域时,会执行回调函数。在回调函数中,将 "data-src" 属性的值赋给 "src" 属性,实现图片加载。 ```javascript // 创建 IntersectionObserver 实例 const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const lazyImage = entry.target; lazyImage.src = lazyImage.dataset.src; lazyImage.classList.remove('lazyload'); observer.unobserve(lazyImage); } }); }); // 获取所有需要懒加载的图片元素 const lazyImages = document.querySelectorAll('.lazyload'); // 遍历所有图片元素,将其添加到 IntersectionObserver 实例中进行观察 lazyImages.forEach(lazyImage => { observer.observe(lazyImage); }); ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值