JavaScript实现图片懒加载的三种常用方法总结
作者:sevenBoy
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
,将每张图片作为参数传入该函数,并返回true
或false
// 可视区域判断函数 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
不包含border
和margin
- 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
实例上的observe
和unobserve
方法,注册或取消监听事件。 - 利用
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图片懒加载的资料请关注脚本之家其它相关文章!