效果
思考:假如给你50+张图片,你如何实现懒加载?
思路:
- 加载loading图片:先在显示9张带着loading图片的div块进行占位
- 获取后台数据,根据请求图片数量替换并生成同等数量的带着loading的div块
- 利用Image()对象先将图片加载至内存,
- 待加载完毕再将图片替换loading.png;
知识预热:
利用图片到 浏览器顶部的距离offsetTop的距离=浏览器可视窗口的距离clientHeight+滚动条距离scrollHeight 的时候开始加载图片。
可视窗口获取api:
- 原生方法:window.innerHeight 标准浏览器及IE9+
- document.documentElement.clientHeight 标准浏览器及低版本IE标准模式
- document.body.clientHeight 低版本混杂模式
- jQuery方法: $(window).height()
滚动条获取api:
- 原生方法:window.pageYoffset——IE9+及标准浏览器
- document.documentElement.scrollTop 兼容ie低版本的标准模式
- document.body.scrollTop 兼容混杂模式;
- jQuery方法:$(document).scrollTop();
获取元素本身的位置信息:
- 原生:ele.offsetTop获取ele距离顶部的距离,距
offsetParent
元素的顶部内边距的距离。 - jQuery:(o).offset().top元素距离文档顶的距离。
整体实现
json数据和项目结构
- 在这,我用fetch进行异步请求数据。然后进行div块渲染。
- 数据请求后直接执行 判断图片是否在可视 界面 ;执行fn();
- 对window添加监听函数
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片懒加载</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.container {
padding: 10px;
background-color: darkkhaki;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.item {
border: 1px solid darkgray;
background-color: white;
margin: 10px;
padding: 10px;
width: 400px;
height: 400px;
text-align: center;
line-height: 400px;
}
.item img {
width: 50px;
height: 50px;
}
.item img.over {
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<div class="container">
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
<div class="item"><img src="./img/loading.gif"></div>
</div>
</body>
<script>
let divItem = document.querySelector('.container'),
str = '';
//fetch进行异步请求
fetch('./data.json').then(res => {
return res.json();
}).then(res => {
let url = res;
for (let i = 0; i < url.length; i++) {
str += `<div class="item"><img src="./img/loading.gif" data-src=${url[i]}></div>`;
}
//本来想法是向末尾添加元素
// divItem.insertAdjacentHTML('beforeend', str);
divItem.innerHTML = str;
let imgs = document.querySelectorAll('img');
// 获取元素距离顶部距离
function getTop(o) {
let T = o.offsetTop;
return T;
}
//判断图片是否应该渲染
function fn() {
//可视高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight;
// 滚动条距离
let scrollHeight = pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
for (let i = 0; i < imgs.length; i++) {
if (clientHeight + scrollHeight > getTop(imgs[i])) {
// 设置延时,形成异步加载效果
setTimeout(() => {
// 创建一个临时图片,这个图片在内存中不会到页面上去。实现隐形加载;在内存中加载完毕再渲染
let temp = new Image();
temp.src = imgs[i].getAttribute('data-src');
temp.onload = function () {
//在内存中加载完毕,替换真图片
imgs[i].className = 'over';
imgs[i].src = imgs[i].getAttribute('data-src');
}
}, 1500)
}
}
// 全部加载完毕后,去掉监听事件
if (document.querySelectorAll('.over').length == imgs.length) {
window.removeEventListener('scroll', fn, false);
}
}
请求回来后,直接执行,进行可视界面的图片加载。
fn();
window.addEventListener('scroll', fn, false);
});
</script>
</html>