如果一个页面图片过多,则需要一次性请求所有图片。对于用户侧来说,会浪费大量的流量去下载可能不需要的图片,对于服务端来说,则会占用大量的带宽。
一、原理
浏览器通过img的src属性来判断是否发起请求,当图片进入浏览器可视区域时,用js取到该图片的data-src的值赋给src。
二、实现
1、因为需要在scroll中来去判断是否在视口内,但是scroll触发非常频繁,因此需要结合节流来去实现。节流代码:
function throttle(fn, delay) {
let valid = true;
return function() {
if (!valid) {
return false;
}
valid = false;
setTimeout(() => {
fn();
valid = true;
}, delay);
}
}
2、判断是否处于视口之内
Element.getBoundingClientRect()方法返回一个 DOMRect对象,其提供了元素的大小及其相对于视口的位置。
返回值是一个 DOMRect对象,是包含整个元素的最小矩形(包括padding 和border-width )。该对象使用left 、top 、 right、 bottom 、x 、y、width 和height这几个以像素为单位的只读属性描述整个矩形的位置和大小。除了width和 height以外的属性是相对于视图窗口的左上角来计算的。
function isElementInViewport (el) {
const { left, top } = el.getBoundingClientRect();
const viewportW = window.innerWidth || document.body.clientWidth;
const viewportH = window.innerHeight || document.body.clientHeight;
return top <= viewportH && left <= viewportW;
}
3、实现
因为scroll只有当滚动的时候才会触发,因此需要先加载首屏的图片
const imgs = document.querySelectorAll('img');
function lazyLoad(imgs) {
let currentIndex = 0;
function loadImg() {
while (currenIndex < imgs.length) {
const img = imgs[currentIndex];
if (isElementInViewport(img)) {
const src = img.getAttribute('data-src');
img.src = src;
currenIndex++;
} else {
break;
}
}
}
loadImg();
return loadImg;
}
window.onload = function() {
window.addEventListener('scroll', throttle(lazyLoad(imgs), 200));
}