这是我参与更文挑战的第12天,活动详情查看: 更文挑战
图片懒加载
定义
什么是图片懒加载? 是一种提升页面加载速度的优化方式
假设我们页面有很多图片,如果我们一进入页面就加载所有图片,现在的图片都有几百k,那加载完耗时就很久,用户都跑光了图片还没加载好,所以就有图片懒加载
这种方式
图片懒加载,就是页面向下滚动,当图片快到我们的可视区域之前,才去加载图片,不在我们的可视区域我们就不加载,这就是图片懒加载
,可以更好的节省带宽,提高页面加载速度。
常规实现方法
一般常规的实现方法,是监听页面的滚动事件,在快要滚动到图片的位置之前,把img的src替换成真实的src,后面的图片依次类推。简易版代码如下
// 检查是否在可视区域
function checkDomIsInVisibleArea(dom) {
// 间距,就是提前多少间距就认为是在可视区域里面
const distance = 100
const rect = dom.getBoundingClientRect()
return rect.top < window.innerHeight + distance && rect.top > -distance && rect.left < window.innerWidth + distance && rect.left > -distance
}
// 防抖函数
function debounce(fn, delay = 100) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn(...args)
}, delay)
}
}
// 懒加载
function lazyLoad() {
const imgs = document.querySelectorAll('img')
imgs.forEach(dom => {
// 在可视区域并且有data-src
if (checkDomIsInVisibleArea(dom) && dom.dataset['src']) {
dom.setAttribute('src', dom.dataset['src'])
dom.removeAttribute('data-src')
}
})
}
// 监听滚动事件
window.addEventListener('scroll', debounce(lazyLoad))
复制代码
今天看到还有一个原生api有个神器也可以实现,那就是IntersectionObserver
,下面咱们好好来讲讲。
IntersectionObserver
翻译为交叉观察者
,可以异步观察目标元素与其祖先元素或顶级文档视窗(viewport)的交叉状态,简而言之就是监听元素,如果该元素处于可视区域或者滚动经过可视区域,会触发回调函数。
IntersectionObserver API是异步的,不随着目标元素的滚动同步触发,不用担心会影响网页性能
语法
const observer = new IntersectionObserver(callback[, options]) // 返回 IntersectionObserver实例
callback
如果元素和祖先元素发生交叉
,就执行此回调函数,返回2个参数
-
entries,包含IntersectionObserverEntry对象的数组
打印的IntersectionObserverEntry对象
IntersectionObserverEntry对象说明如下
属性 说明 boundingClientRect 目标元素的位置信息 intersectionRatio 目标元素在可视区域的占比 intersectionRect 目标元素与可视区域的交叉位置信息 isIntersecting 目标元素是否正在可视区域 rootBounds 可视区域的位置信息 target 目标元素 time 记录时间原点到发生交叉的时间戳,毫秒
options
可选,对象类型,配置参数如下
属性 | 说明 |
---|---|
root | 当作可视区域的Element对象,默认是浏览器的视口 |
rootMargin | 扩大或者缩小可视区域的的大小,语法大致和CSS中的margin属性等同,默认是0px 0px 0px 0px |
threshold | 规定了目标元素占可视区域多大比例,才触发callback ,可以是数值或者数组。默认是0, 就是监听元素一出现在可视区域就触发,最大是1, 整个元素都出现了才触发。也可以设置数组,[0, 0.25, 1], 一进入触发(0%)回调,当进入到25%时候触发回调,整个元素都出现(100%)也触发回调 |
IntersectionObserver实例方法
-
observe(Element)
开始监听一个目标元素, 参数是
目标元素的节点
-
unobserve(Element)
取消监听一个目标元素, 参数是
目标元素的节点
-
takeRecords()
无参数,返回所有目标元素的IntersectionObserverEntry对象的数组
-
disconnect()
无参数,断开连接,停止IntersectionObserver的所有监听
图片懒加载-IntersectionObserver实现
// 创建交叉观察实例
const observer = new IntersectionObserver(entries => {
entries.forEach(item => {
// 如果正在交叉
if (item.isIntersecting) {
item.target.setAttribute('src', item.target.dataset['src'])
// 取消监听
observer.unobserve(item.target)
}
})
}, {
threshold: .1
})
const imgs = document.querySelectorAll('img')
// 遍历imgs开始监听
imgs.forEach(item => {
// 开始监听
observer.observe(item)
})
复制代码
兼容性
目前兼容性不是很好,查看下图,数据来自caniuse
总结
IntersectionObserver这个api很好用,图片懒加载只是其中的一个用法,还可以用来无限滚动
,曝光埋点
,滚动动画
等等,大家先学会,后面有需要就可以用上啦,希望对你们有帮助。感谢~