懒加载的3种实现方式

38次阅读

共计 10766 个字符,预计需要花费 27 分钟才能阅读完成。

优势

性能收益:浏览器加载图片、decode、渲染都需要耗费资源,懒加载能节约性能消耗,缩短 onload 事件时间。
节约带宽:这个不需要解释。

通常,我们在 html 中展示图片,会有两种方式:

img 标签
css background-image

img 的懒加载实现
img 有两种方式实现懒加载:
事件监听 (scroll、resize、orientationChange)
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>event</title>
<style>
img {
background: #F1F1FA;
width: 400px;
height: 300px;
display: block;
margin: 10px auto;
border: 0;
}
</style>
</head>
<body>
<img src=”https://ik.imagekit.io/demo/img/image1.jpeg?tr=w-400,h-300″ />
<img src=”https://ik.imagekit.io/demo/img/image2.jpeg?tr=w-400,h-300″ />
<img src=”https://ik.imagekit.io/demo/img/image3.jpg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image2.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image3.jpg?tr=w-400,h-300″ /> –>
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image5.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image6.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image7.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image8.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image9.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-400,h-300″ />
<script>
document.addEventListener(“DOMContentLoaded”, function() {
var lazyloadImages = document.querySelectorAll(“img.lazy”);
var lazyloadThrottleTimeout;

function lazyload () {
if(lazyloadThrottleTimeout) {
clearTimeout(lazyloadThrottleTimeout);
}

lazyloadThrottleTimeout = setTimeout(function() {
var scrollTop = window.pageYOffset;
lazyloadImages.forEach(function(img) {
if(img.offsetTop < (window.innerHeight + scrollTop)) {
img.src = img.dataset.src;
img.classList.remove(‘lazy’);
}
});
if(lazyloadImages.length == 0) {
document.removeEventListener(“scroll”, lazyload);
window.removeEventListener(“resize”, lazyload);
window.removeEventListener(“orientationChange”, lazyload);
}
}, 20);
}

document.addEventListener(“scroll”, lazyload);
window.addEventListener(“resize”, lazyload);
window.addEventListener(“orientationChange”, lazyload);
});
</script>
</body>
</html>
Intersection Observer(兼容性问题)
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>observer</title>
<style>
img {
background: #F1F1FA;
width: 400px;
height: 300px;
display: block;
margin: 10px auto;
border: 0;
}
</style>
</head>
<body>
<img src=”https://ik.imagekit.io/demo/img/image2.jpeg?tr=w-400,h-300″ />
<img src=”https://ik.imagekit.io/demo/img/image3.jpg?tr=w-400,h-300″ /> –>
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image1.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image2.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image3.jpg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image5.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image6.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image7.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image8.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image9.jpeg?tr=w-400,h-300″ />
<img class=”lazy” data-src=”https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-400,h-300″ />
<script>
document.addEventListener(“DOMContentLoaded”, function() {
var lazyloadImages = document.querySelectorAll(“.lazy”);
var imageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var image = entry.target;
image.src = image.dataset.src;
image.classList.remove(“lazy”);
imageObserver.unobserve(image);
}
});
});
lazyloadImages.forEach(function(image) {
imageObserver.observe(image);
});
});
</script>
</body>
</html>
background-image 的实现
background-image 的实现跟 img 的原理基本是一样的,区别是在对 class 的处理上:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>background</title>
<style>
body {
margin: 0;
}
.bg {
height: 200px;
}
#bg-image.lazy {
background-image: none;
background-color: #F1F1FA;
}
#bg-image {
background-image: url(“https://ik.imagekit.io/demo/img/image1.jpeg?tr=w-400,h-300″);
background-size: 100%;
}
</style>
</head>
<body>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<div id=”bg-image” class=”bg lazy”></div>
<script>
document.addEventListener(“DOMContentLoaded”, function() {
var lazyloadImages = document.querySelectorAll(“.lazy”);
var imageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var image = entry.target;
image.classList.remove(“lazy”);
imageObserver.unobserve(image);
}
});
});
lazyloadImages.forEach(function(image) {
imageObserver.observe(image);
});
});
</script>
</body>
</html>
渐进式懒加载
渐进式懒加载,指的是存在降级处理,通常 html 形式如下:
<a href=”full.jpg” class=”progressive replace”>
<img src=”tiny.jpg” class=”preview” alt=”image” />
</a>
这样的代码会有 2 个好处:

如果 js 执行失败,可以点击预览
大小与实际图一致的占位 data URI,避免 reflow

最终的代码如下:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>progressive</title>
<style>
a.progressive {
position: relative;
display: block;
overflow: hidden;
outline: none;
}
a.progressive:not(.replace) {
cursor: default;
}
a.progressive img {
display: block;
width: 100%;
max-width: none;
height: auto;
border: 0 none;
}
a.progressive img.preview {
filter: blur(2vw);
transform: scale(1.05);
}
a.progressive img.reveal {
position: absolute;
left: 0;
top: 0;
will-change: transform, opacity;
animation: reveal 1s ease-out;
}
@keyframes reveal {
0% {transform: scale(1.05); opacity: 0;}
100% {transform: scale(1); opacity: 1;}
}
</style>
</head>
<body>
<a href=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5.jpg” data-srcset=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5.jpg 800w, https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5big.jpg 1600w” class=”progressive replace”>
<img src=”data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2NjIpLCBxdWFsaXR5ID0gNzAK/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgABQAUAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A5yC3e2S3gM7OEQHdgA57VTuLAPqUoaUk7yM7R2BPSiivS5VN8stjmk2ldGVM3lyshG7bxk0UUV4skk2jdN2P/9k=” class=”preview” alt=”palm trees” />
</a>
<a href=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature2.jpg” class=”progressive replace”>
<img src=”http://lorempixel.com/20/15/nature/2/” class=”preview” alt=”sunset” />
</a>
<a href=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature3.jpg” class=”progressive replace”>
<img src=”http://lorempixel.com/20/15/nature/3/” class=”preview” alt=”tide” />
</a>
<a href=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5.jpg” data-srcset=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5.jpg 800w, https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature5big.jpg 1600w” class=”progressive replace”>
<img src=”data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2NjIpLCBxdWFsaXR5ID0gNzAK/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgABQAUAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A5yC3e2S3gM7OEQHdgA57VTuLAPqUoaUk7yM7R2BPSiivS5VN8stjmk2ldGVM3lyshG7bxk0UUV4skk2jdN2P/9k=” class=”preview” alt=”palm trees” />
</a>
<a href=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature2.jpg” class=”progressive replace”>
<img src=”http://lorempixel.com/20/15/nature/2/” class=”preview” alt=”sunset” />
</a>
<a href=”https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/nature3.jpg” class=”progressive replace”>
<img src=”http://lorempixel.com/20/15/nature/3/” class=”preview” alt=”tide” />
</a>
<script>
window.addEventListener(‘load’, function() {
var pItem = document.getElementsByClassName(‘progressive replace’), timer;

window.addEventListener(‘scroll’, scroller, false);
window.addEventListener(‘resize’, scroller, false);
inView();

function scroller(e) {
timer = timer || setTimeout(function() {
timer = null;
requestAnimationFrame(inView);
}, 300);
}

function inView() {
var scrollTop = window.pageYOffset;
var innerHeight = window.innerHeight;
var p = 0;
while (p < pItem.length) {
var offsetTop = pItem[p].offsetTop;
if (offsetTop < (scrollTop + innerHeight)) {
loadFullImage(pItem[p]);
pItem[p].classList.remove(‘replace’);
}
else p++;
}
}

function loadFullImage(item) {
var img = new Image();
if (item.dataset) {
img.srcset = item.dataset.srcset || ”;
img.sizes = item.dataset.sizes || ”;
}
img.src = item.href;
img.className = ‘reveal’;
if (img.complete) addImg();
else img.onload = addImg;

function addImg() {
item.addEventListener(‘click’, function(e) {e.preventDefault(); }, false);
item.appendChild(img).addEventListener(‘animationend’, function(e) {
var pImg = item.querySelector(‘img.preview’);
if (pImg) {
e.target.alt = pImg.alt || ”;
item.removeChild(pImg);
e.target.classList.remove(‘reveal’);
}
});
}

}

}, false);
</script>
</body>
</html>
现成库
推荐下面这个库,使用非常简单:https://www.npmjs.com/package/lozad

正文完
 0