- Published on
JavaScript实现懒加载图片、动画
- Authors
- Name
- Monster Cone
懒加载是前端一种常见的优化手段,下面将介绍两种常见的懒加载实现
方法一 (getBoundingClientRect API)
该方法优点是兼容性较好,所有浏览器都支持。代码如下
const innerHeight = window.innerHeight
const debounce = (func, delay = 200) => {
let timer
return function (...args) {
const context = this
clearTimeout(timer)
timer = setTimeout(() => {
func.apply(context, args)
}, delay)
}
}
const lazyLoading = () => {
let imgs = [...document.querySelectorAll('img')]
imgs.forEach((el) => {
const { top, height } = el.getBoundingClientRect()
if (innerHeight - top > 0) {
el.classList.add('animation')
el.src = el.dataset.src
}
if (top + height < 0 || top > innerHeight) {
el.classList.remove('animation')
}
})
}
window.addEventListener('scroll', debounce(lazyLoading, 300), false)
window.onload = lazyLoading
使用 getBoundingClientRect 获取元素高度和距离顶部的距离,计算是否在可视区内,如果在可视区内就给图片设置 src 属性或者添加动画 class,如果不在可视区内就移除动画 class,使元素在下次滚动到可视区时还能有动画效果。因为有些图片一开始就在顶部,这时候并不会触发 scroll 事件,就需要在页面加载完成时调用一次 lazyLoading 方法。
优化点:如果只需要使用图片懒加载,可以将选择器改为 document.querySelectorAll("img[src='']"),这样只会遍历还没加载图片的 img 元素。
方法二 (IntersectionObserver API)
IntersectionObserver 不支持 IE 浏览器,也不支持一些低版本的浏览器,但在今日,对于一些主流的浏览器兼容是足够的。它更容易实现。代码如下
let observer
const loadImage = (entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
const { src } = entry.target.dataset
entry.target.src = src
entry.target.classList.add('animation')
} else {
entry.target.classList.remove('animation')
}
})
}
window.onload = () => {
observer = new IntersectionObserver(loadImage)
let imgs = [...document.querySelectorAll('img')]
imgs.forEach((el) => {
observer.observe(el)
})
}
首先我们在页面加载完成时注册一个 IntersectionObserver 实例,同时获取所有的 img 元素并使用 IntersectionObserver 实例进行监听。callback 通常会在元素进入视口和离开视口时触发,如果你在实例化 IntersectionObserver 的时候配置了 threshold 属性,它也会在 threshold 条件下触发。
回调函数接受两个参数,一个 IntersectionObserverEntry 对象,一个触发 IntersectionObserver 的实例
IntersectionObserverEntry 中包含如下属性
- boundingClientRect(触发元素宽高属性,同 getBoundingClientRect)
- intersectionRatio(相交比例)
- intersectionRect(相交区域)
- isIntersecting(与根相交)
- rootBounds(观察者根元素)
- target(相交元素)
- time(相交时间戳)
我们只需要 intersectionRatio 相交比例,在它大于 0 时我们设置 img 标签的 src 属性或者动画 class,在等于 0 时移除动画 class。
优化点:如果只需要使用图片懒加载,可以在设置了 src 属性后通过 observer.unobserve 方法移除元素的监听。
可以根据兼容性需要选择合适的实现方案