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创建数组的三种方式

    详解JavaScript创建数组的三种方式

    这篇文章主要介绍了JavaScript创建数组的三种方式:直接声明, 以对象方式创建数组和使用 Array.from() 方法创建,并通过代码示例讲解的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-06-06
  • javascript完美拖拽的实现方法

    javascript完美拖拽的实现方法

    这篇文章介绍了javascript完美拖拽的实现方法,有需要的朋友可以参考一下
    2013-09-09
  • 使用fabric实现恢复和撤销功能的实例详解

    使用fabric实现恢复和撤销功能的实例详解

    在图形编辑器中,撤销和恢复是一个非常常见的功能了,但是搜了下,网上好像也没有太多相关的文章 可能是因为canvas相关的资料确实太少了吧,所以本文给大家介绍了如何基于 fabric 实现恢复、撤销功能,需要的朋友可以参考下
    2024-06-06
  • Jsonp 跨域的原理以及Jquery的解决方案

    Jsonp 跨域的原理以及Jquery的解决方案

    JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。
    2010-05-05
  • Webpack打包时将文件内联方法实现

    Webpack打包时将文件内联方法实现

    本文主要介绍了Webpack打包时将文件内联方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Javascript ES6中数据类型Symbol的使用详解

    Javascript ES6中数据类型Symbol的使用详解

    Symbol类型是es6新增的一个数据类型,Symbol值通过Symbol函数生成Symbol类型是保证每个属性的名字都是独一无二的,对于一个对象由对个模块构成的情况非常有用,本文主要介绍了Javascript ES6中数据类型Symbol使用的相关资料,需要的朋友可以参考下。
    2017-05-05
  • webpack打包并将文件加载到指定的位置方法

    webpack打包并将文件加载到指定的位置方法

    下面小编就为大家分享一篇webpack打包并将文件加载到指定的位置方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • Mint-UI时间组件起始时间问题及时间插件使用

    Mint-UI时间组件起始时间问题及时间插件使用

    这篇文章主要介绍了Mint-UI时间组件起始时间问题的解决方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • JS实现点击文字对应DIV层不停闪动效果的方法

    JS实现点击文字对应DIV层不停闪动效果的方法

    这篇文章主要介绍了JS实现点击文字对应DIV层不停闪动效果的方法,实例分析了javascript操作div层的效果,非常实用,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • javascript call和apply方法

    javascript call和apply方法

    用于改变方法的当前对象
    2008-11-11

最新评论