1 几个和图片懒加载相关的API
clientHeight,clientWidth
element.clientHeight
element.clientWidth
MDN上的解释
clientHeight`可以计算为:CSS `height`+ CSS `padding`- 水平滚动条的高度(如果存在)
clientWidth`可以计算为:CSS `width`+ CSS `padding`- 垂直滚动条的高度(如果存在)
直观的图解
offSetTop
element.offsetTop
MDN上的解释
它返回当前元素相对于其offsetParent元素的顶部内边距的距离
getBoundingClientRect
Element.getBoundingClientRect()
MDN上的解释
Element.getBoundingClientRect() 方法返回元素的大小和相对于视口的位置。
如果是标准盒子模型,元素的尺寸等于`width/height`+ `padding`+`border-width`的总和。如果`box-sizing: border-box`,元素的的尺寸等于`width/height`如果:offsetTop-scroolTop<clientHeight,则图片进入了可视区内,则被请求
返回的结果是包含完整元素的最小矩形,并且拥有`left`,`top`,`right`,`bottom`,`x`,`y`,`width`,和 `height`这几个以像素为单位的只读属性用于描述整个左边缘
直观的图解
IntersectionObserver
IntersectionObserver接口(从属于Intersection Observer API)为开发者提供了一种可以异步监听目标元素与其祖先或视窗(viewport)交叉状态的手段。祖先元素与视窗(viewport)被称为根(root)
具体使用方法参考我的文章 IntersectionObserver接口详解
2 图片懒加载思路
就一个思路,只有图片进入了可视区内才被请求
方法一
如果:offsetTop-scroolTop<clientHeight,则图片进入了可视区内,则被请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图片懒加载</title>
<style>
img {
width: 100%;
height: 100%;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div>
<img data-src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg" alt="">
</div>
</body>
<script>
const imgs = document.querySelectorAll('img')
//如果当前元素offsetParent存在则向上循环直至offsetParent不存在
function getTop(e) {
let T = e.offsetTop
while (e = e.offsetParent) {
T += e.offsetTop
}
return T
}
function lazyLoad(imgs) {
const H = document.documentElement.clientHeight//获取可视区域高度
const S = document.documentElement.scrollTop || document.body.scrollTop
for (let i = 0; i < imgs.length; i++) {
if (H + S > getTop(imgs[i])) {
imgs[i].src = imgs[i].getAttribute('data-src')
}
}
}
window.onload = window.onscroll = function () { //onscroll()//滚动时触发
lazyLoad(imgs)
}
</script>
</html>
方法二
Element.getBoundingClientRect().top<=clientHeight`时,图片是在可视区域内的
js代码如下
const imgs = document.querySelectorAll('img');
function isIn(el) {
const top = el.getBoundingClientRect().top;
const clientHeight = window.innerHeight;
return top <= clientHeight;
}
//检查图片是否在可视区内,如果不在,则加载
function check() {
Array.from(imgs).forEach(function(el){
if(isIn(el)){
loadImg(el);
}
})
}
function loadImg(el) {
if(!el.src){
cosnt source = el.dataset.src;
el.src = source;
}
}
window.onload = window.onscroll = function () { //onscroll()滚动时触发
check();
}
方法三
使用IntersectionObserver接口
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图片懒加载</title>
<style>
img {
width: 100%;
height: 250px;
}
</style>
</head>
<body>
<img data-src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg" alt="">
<img data-src="https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg" alt="">
</body>
<script>
let imgList = document.querySelectorAll('img')
let observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src
observer.unobserve(entry.target)
}
})
})
imgList.forEach(img => {
observer.observe(img)
})
</script>
</html>