最近在过面试题发现图片懒加载也有人问,正常开发就是在图片加上loading=“lazy”咯,但是底层原理你知道吗,我这里总结一下
传统js+节流
这种方法比较好理解,但是要加一个节流,不然会多次触发,一打开页面马上就全部加载了,不贴合实际的开发场景。所以加个节流会好点。根本思路就是滚动条的高度(不同浏览器适配不同)document.body.scrollTop||document.documentElement.scrollTop||window.pageYOffset,加上页面可视的高度window.innerHeight大于图片距离顶部高度img.offsetTop。
代码:
` function throttle(fn, delay) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
timer = null
fn.apply(this, args)
}, delay)
}
}
}
const imglist = document.querySelectorAll("img")
console.log(imglist)
window.addEventListener("scroll", throttle(lazyload, 500));
function lazyload() {
let seeheight = window.innerHeight;
let scrollnum = document.documentElement.scrollTop || document.body.scrollTop;
for (let ig of imglist) {
if (ig.offsetTop < seeheight + scrollnum) {
console.log("触发了")
let trueSrc = ig.getAttribute("data-src")
ig.setAttribute("src", trueSrc)
}
}
}`
IntersectionObserver
IntersectionObserver API,可以自动"观察"元素是否可见,由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。
IntersectionObserverEntry 对象
-
time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
-
target:被观察的目标元素,是一个 DOM 节点对象
-
rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
-
boundingClientRect:目标元素的矩形区域的信息
-
intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
-
intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0 `
const observer=new IntersectionObserver(callback=>{ callback.forEach(item=>{ if(item.isIntersecting){ const image=item.target; const trueimg=image.getAttribute('data-src') image.setAttribute('src',trueimg) // 加载完后不用观察了 observer.unobserve(image) } }) }) imaglist.forEach(item=>{ observer.observe(item) })`