懒加载原理及实现
1.懒加载原理
一张图片就是一个<img>标签,浏览器发起图片请求,请求是根据<img>的src属性加载图片,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给<img>的src赋值,这样浏览器就加载不到图片了,等到图片进入可视区域再给src赋值。
2.懒加载思路及实现
实现懒加载有四个步骤,如下:
1.加载loading定位图片
2.判断哪些图片要加载【重点】
3.隐形加载图片
4.替换真图片
懒加载原理
视口高度:document.documentElement.clientHeight
当前元素相对于其 offsetParent 元素的顶部的距离:HTMLElement.offsetTop
滚动条移动高度:document.documentElement.scrollTop
如上图所示,当图片距离顶部的距离offsetTop等于可视区域clientHeight和滚动区域高度scrollTop之和时说明图片马上就要进入可视区了,就是说当offsetTop<=clientHeight + scrollTop时,图片在可视区。
示例
懒加载
css
<style>
.container {
width: 500px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.container img {
width: 100%;
}
</style>
html
<div class="container">
<img src="images/temp.jpg" alt="" data-src="images/img-1.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-2.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-3.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-4.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-5.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-6.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-7.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-8.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-9.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-10.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-11.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-12.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-13.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-14.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-15.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-16.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-17.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-18.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-19.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-20.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-21.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-22.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-23.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-24.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-25.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-26.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-27.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-28.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-29.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-30.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-31.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-32.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-33.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-34.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-35.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-36.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-37.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-38.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-39.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-40.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-41.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-42.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-43.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-44.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-45.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-46.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-47.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-48.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-49.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-50.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-51.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-52.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-53.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-54.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-55.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-56.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-57.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-58.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-59.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-60.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-61.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-62.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-63.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-64.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-65.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-66.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-67.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-68.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-69.jpg">
<img src="images/temp.jpg" alt="" data-src="images/img-70.jpg">
</div>
js
// 所有图片
const imgs = document.querySelectorAll('.container > img');
// 图片加载函数
function imgLoad() {
// 视口高度
let viewHeight = document.documentElement.clientHeight;
// 滚动距离
let scrollTop = document.documentElement.scrollTop;
imgs.forEach((img) => {
// 判断是否进入视口
if (img.offsetTop <= viewHeight + scrollTop) {
setTimeout(() => {
img.src = img.dataset.src;
}, 500);
}
});
}
// 加载时
window.addEventListener('load', imgLoad);
// 滚动条
window.addEventListener('scroll', imgLoad);
// 视口变化时
window.addEventListener('resize', imgLoad);
轮播图
css
/* 初始化 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
}
/* 轮播图的容器 */
.container {
width: 62.5em;
height: 22em;
margin: 1em auto;
/* 转为定位元素/定位父级 */
position: relative;
}
/* 图片组 */
.container > .imgs img {
width: 100%;
height: 100%;
/* 默认全部隐藏 */
display: none;
/* 将所有的图片进行绝对定位,确保每一次只看到一张,所有图片共享这个容器 */
position: absolute;
left: 0;
top: 0;
}
/* 设置默认显示的图片(第一张) */
.container > .imgs img.active {
display: block;
}
/* 按钮组(独立按钮) */
.container > .btns {
position: absolute;
left: 0;
right: 0;
bottom: 0;
/* 水平居中 */
text-align: center;
}
.container > .btns a {
/* 转成行内块元素: 即能水平排列,双支持宽度设置 */
display: inline-block;
padding: 0.5em;
margin: 0 0.2em;
background-color: #fff;
border-radius: 50%;
}
.container > .btns a.active {
background-color: #000;
}
/* 翻页按钮 */
.container .skip a {
position: absolute;
width: 2.5rem;
height: 5rem;
line-height: 5rem;
text-align: center;
opacity: 0.3;
top: 9rem;
font-weight: lighter;
font-size: 2rem;
background-color: #ccc;
}
.container .skip .prev {
left: 0;
}
.container .skip .next {
right: 0;
}
.container .skip *:hover {
opacity: 0.6;
color: #666;
}
html
<div class="container">
<!-- 1. 图片组 -->
<nav class="imgs">
<a href="#"><img src="banner/banner1.jpg" alt="" data-index="1" class="active" /></a>
<a href="#"><img src="banner/banner2.jpg" alt="" data-index="2" /></a>
<a href="#"><img src="banner/banner3.jpg" alt="" data-index="3" /></a>
<a href="#"><img src="banner/banner4.jpg" alt="" data-index="4" /></a>
</nav>
<!-- 2. 图片中下部的小按钮 -->
<nav class="btns">
</nav>
<!-- 3. 翻页 -->
<nav class="skip">
<a href="#" class="prev"><</a>
<a href="#" class="next">></a>
</nav>
</div>
javascript
// 获得元素
const imgs = document.querySelectorAll('.container >.imgs img');
const btnGroup = document.querySelector('.container > .btns');
const skips = document.querySelector('.container > .skip');
// 创建小按钮的函数
function createBtns(ele,imgLength) {
// 临时父类
let tempBtns = document.createDocumentFragment();
for (let i = 0; i < imgLength; i++) {
let a = document.createElement('a');
a.href = '#';
a.dataset.index = `${i + 1}`;
if ( i === 0) {
a.classList.add('active');
}
tempBtns.append(a);
}
ele.append(tempBtns);
}
// 创建按钮
createBtns(btnGroup,imgs.length);
const btns = document.querySelectorAll('.container > .btns > *');
// 获得activeEle
function getActiveEle(eles) {
let activeEle = [...eles].filter((ele)=>ele.classList.contains('active'));
return activeEle[0];
}
// 设置active元素
function setActiveEle(Index) {
[imgs,btns].forEach((items) =>{
getActiveEle(items).classList.remove('active');
items.forEach((item)=>{
if (item.dataset.index == Index) {
item.classList.add('active');
}
});
});
}
// 小按钮点击事件
btns.forEach((item)=>{item.addEventListener('click',(ev)=>{setActiveEle(ev.target.dataset.index)})});
// 获得当前active元素index
let currentEleIndex = getActiveEle(imgs).dataset.index;
// 上页 下页
skips.querySelector('.next').addEventListener('click', nextEle);
skips.querySelector('.prev').addEventListener('click', prevEle);
// 下页函数
function nextEle(ev) {
if ( ++currentEleIndex > imgs.length) {
currentEleIndex = imgs[0].dataset.index;
}
setActiveEle(currentEleIndex);
}
// 上页函数
function prevEle(ev){
if ( --currentEleIndex < imgs[0].dataset.index) {
currentEleIndex = imgs[imgs.length - 1].dataset.index;
}
setActiveEle(currentEleIndex);
}
// 轮播
const container = document.querySelector('.container');
container.addEventListener('mouseover', stopRun, false);
container.addEventListener('mouseout', startRun, false);
container.addEventListener('run', nextEle);
// 定时器
let timer = [];
const evt = new Event('run');
function startRun(ev) {
timer = setInterval('container.dispatchEvent(evt)',2000);
}
function stopRun(ev) {
clearInterval(timer);
}