为什么要懒加载?
懒加载是一种网页性能优化的方式,它能极大的提升用户体验。
假如访问某个页面,加载这个页面全部的图片(即使这些图片并不处在用户的当前的视窗中),在弱网环境或者网速较慢的环境下,这些“冗余”图片的下载会占用用户本来就非常有限的带宽,影响用户体验所以对于网站的图片,优化的方法就是懒加载(按需加载)。
实现原理
进入页面的时候,只请求可视区域的图片资源, 不在可视区域内的图片,等将要出现时动态加载。
将img标签src设置为一张默认小图片,然后定义data-src
(这个属性可以自定义命名,我才用data-src)属性指向真实的图片。src
需设置一张默认的图片,否则当src
为空时也会向服务器发送一次请求。
一个简单的实现
设置data-src, 通过js加载真正的图片。
// img-load.css
img[data-src] {
filter: blur(0.2em);
}
img {
filter: blur(0em);
transition: filter 0.5s;
}
// img-load.js
function lazyLoad(){
const imageToLazy = document.querySelectorAll('img[data-src]');
const loadImage = function (image) {
image.setAttribute('src', image.getAttribute('data-src'));
image.addEventListener('load', function() {
image.removeAttribute("data-src");
})
}
imageToLazy.forEach(function(image){
loadImage(image);
})
}
lazyLoad();
return (
...
![](deafult.png)
...
);
监听滚动加载图片
先加载出现在视窗中的图片, 当页面将要滚动到不在视窗内的图片时,加载图片。
- 用IntersectionObserver实现当图片滚动到视窗后再加载该图片, 考虑到手机兼容性问题需要添加polyfill
(function lazyLoad(){
let observer;
const imageToLazy = document.querySelectorAll('img[data-src]');
const loadImage = function (image) {
image.setAttribute('src', image.getAttribute('data-src'));
image.addEventListener('load', function() {
image.removeAttribute("data-src");
})
}
if (window.IntersectionObserver) {
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting || entry.intersectionRatio > 0) {
loadImage(entry.target);
observer.unobserve(entry.target);
}
});
});
}
imageToLazy.forEach(function(image){
if (window.IntersectionObserver && observer) {
observer.observe(image);
} else {
loadImage(image);
}
})
})();
添加
scroll
事件实现图片懒加载。当页面滚动时,scroll
函数会被高频触发,需要通过节流或者requestAnimationFrame优化性能。判断图片是否将要出现在可视区也可根据
getBoundingClientRect()
判断const imgs = document.getElementsByTagName("img"); const imgLength = imgs.length; let currentIndex = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历 const clientHeight = document.documentElement.clientHeight; //可见区域高度 const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滚动条距离顶部高度 function lazyload(event) { for (let i = currentIndex; i < imgLength; i++) { if (clientHeight + scrollTop > imgs[i].offsetTop) { if (imgs[i].getAttribute("src") == "default.jpg") { imgs[i].src = img[i].getAttribute("data-src"); } currentIndex = i + 1; } } } window.addEventListener('scroll',throttle(lazyload, 500, 1000));
- vue指令实现图片懒加载
let timer = null;
let observer;
if (window.IntersectionObserver) {
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting || entry.intersectionRatio > 0) {
if (!entry.target.isLoaded) {
showImage(entry.target, entry.target.data_src);
}
}
});
});
}
function showImage(el, imgSrc) {
const img = new Image();
img.src = imgSrc;
img.onload = () => {
el.src = imgSrc;
el.isLoaded = true;
};
}
export default {
inserted(el, binding, vnode) {
el.data_src = binding.value;
if (window.IntersectionObserver && observer) {
clearTimeout(timer);
observer.observe(el);
const vm = vnode.context;
timer = setTimeout(() => {
vm.$on('hook:beforeDestroy', () => {
observer.disconnect();
});
}, 20);
} else {
el.src = binding.value;
}
},
update(el, binding) {
if (window.IntersectionObserver && observer) {
el.isLoaded = el.data_src !== binding.value;
el.data_src = binding.value;
} else {
el.src = binding.value;
}
},
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。