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

 更新时间:2023年06月18日 16:22:59   作者:sevenBoy  
懒加载是一种对网页性能优化的方式,也是我们经常会用到的技术,这篇文章为大家整理了JavaScript实现图片懒加载的三种常用方法,希望对大家有所帮助

1.前言

1.1 什么是使用图片懒加载

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

1.2 为什么使用图片懒加载

  • 避免首次加载时消耗大量时间,降低页面渲染速度,造成卡顿现象。
  • 按需加载,避免无效图片的加载,减轻服务器压力,节约网络资源。

若不使用图片懒加载,页面启动时,会加载全部的图片资源:

1.3 图片懒加载的实现原理

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

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

2.实现方法

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为该图片的标签元素

  // 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)
      }
    })
  }

以上就是JavaScript实现图片懒加载的三种常用方法总结的详细内容,更多关于JavaScript图片懒加载的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Javascript获取缓存和清除缓存API

    详解Javascript获取缓存和清除缓存API

    本篇文章主要介绍了详解Javascript获取缓存和清除缓存API,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 更改BootStrap popover的默认样式及popover简单用法

    更改BootStrap popover的默认样式及popover简单用法

    这篇文章主要介绍了更改BootStrap popover的默认样式及popover简单用法,需要的朋友可以参考下
    2018-09-09
  • Eval and new funciton not the same thing

    Eval and new funciton not the 

    以前有人会说,new Function的方式是几乎与eval相等,今天我查了一下,确实是不同的东西,说这句话的人太不负责了。关于eval和new function,得到的结果都是一致的,都会叫你不要去使用它们。所以结论就是“不得不”才使用
    2012-12-12
  • js函数的延迟加载实现代码

    js函数的延迟加载实现代码

    延迟加载的函数,第一次调用后,会覆盖原来的老函数,以后再次调用的是新函数,不会再进行条件的判断,提升效率
    2012-10-10
  • javascript打印html内容功能的方法示例

    javascript打印html内容功能的方法示例

    这篇文章主要介绍了javascript打印html内容的小示例,大家参考使用
    2013-11-11
  • ES6基础之 Promise 对象用法实例详解

    ES6基础之 Promise 对象用法实例详解

    这篇文章主要介绍了ES6基础之 Promise 对象用法,结合实例形式详细分析了ES6中 Promise 对象功能、用法及相关操作注意事项,需要的朋友可以参考下
    2019-08-08
  • js使浏览器窗口最大化实现代码(适用于IE)

    js使浏览器窗口最大化实现代码(适用于IE)

    点击最大化按钮后,浏览器的内容填充满显示器,浏览器窗口的边框被挤出显示器。而该js的最大化效果是浏览器的边框在显示器内显示,具体实现如下,感兴趣的朋友可以参考下
    2013-08-08
  • js实现小时钟效果

    js实现小时钟效果

    这篇文章主要为大家详细介绍了js实现小时钟效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • Vue3中使用typescript封装axios的实例详解

    Vue3中使用typescript封装axios的实例详解

    这篇文章主要介绍了使用typescript封装axios的实例代码,为了方便,在vue3的配置里面按需加载element-plus,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • JS 用6N±1法求素数 实例教程

    JS 用6N±1法求素数 实例教程

    显然,当N≥1时,6N,6N+2,6N+3,6N+4都不是素数,只有形如6N+1和6N+5的自然数有可能是素数。所以,除了2和3之外,所有的素数都可以表示成6N±1的形式(N为自然数)。
    2009-10-10

最新评论