.lazy
类标识,用来识别当前容器图片未被真正加载data-url
上.lazy
标识的)判断每个图片是否出现在屏幕中data-url
真实url设置到图片的 src
属性上data-url
和 .lazy
标识lazy.png
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片懒加载</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="container">
</div>
<!-- 模板 -->
<script type="text/template" id="tpl">
<div class="img-view lazy">
<img src="./lazy.png" alt="{{title}}" data-url="{{url}}">
<p>{{title}}</p>
</div>
</script>
<script src="<https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js>"></script>
<script src="utils.js"></script>
<script src="index.js"></script>
</body>
</html>
utils.js 工具函数
function debounce(fn, delay, triggerNow) {
let timer = null;
return function() {
if (timer) window.clearTimeout(timer);
if (triggerNow) {
let exec = !timer;
timer = setTimeout(() => {
timer = null;
}, delay);
if (exec) {
fn.apply(this, arguments);
}
} else {
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
}
}
}
function throttle(fn, delay) {
let canUse = true;
return function() {
if (canUse) {
fn.apply(this, arguments);
canUse = false;
setTimeout(() => {
canUse = true;
}, delay);
}
}
}
index.js 核心实现
;(function() {
let oContainer = document.querySelector('.container'),
photos = [],
tpl = document.getElementById('tpl').innerHTML;
console.log(tpl);
function init() {
// 获取数据
getData(() => {
oContainer.innerHTML = renderList();
imgLazyLoad();
});
// 绑定事件
bindEvent();
}
function bindEvent() {
// 监听页面加载完+滚动事件
// 注意 throttle 节流
window.onload = window.onscroll = throttle(imgLazyLoad, 500);
}
// 判断图片是否需要被加载
function imgLazyLoad() {
// 图片 .img-view 容器默认加上 lazy class 用来表示当前容器中图片需要被加载
var oList = document.querySelectorAll('.img-view.lazy'),
cHeight = document.documentElement.clientHeight,
sTop = document.documentElement.scrollTop || document.body.scrollTop;
console.log("剩余需懒加载图片个数:", oList.length);
oList.forEach(item => {
let img = item.getElementsByTagName('img')[0];
let dataUrl = img.getAttribute('data-url');
// 如果图片 出现在了屏幕内
// 则把真实图片url从属性"data-url"中取出设置到src
// 再删除 "data-url" 属性和 img-view 容器上的 lazy 标识
if (item.offsetTop < cHeight + sTop) {
img.setAttribute('src', dataUrl);
img.removeAttribute('data-url');
item.classList.remove('lazy');
}
});
}
// 获取mock数据
function getData(cb) {
axios.get('<https://jsonplaceholder.typicode.com/photos>').then(res => {
photos = res.data;
cb && cb();
});
}
// 解析模板,绑定数据,生成字符串列表
function renderList() {
let list = '';
photos.forEach(photo => {
list += tpl.replace(/\\{\\{(.*?)\\}\\}/g, (node, key) => {
return {
url: photo.url,
title: photo.title
}[key];
});
});
return list;
}
init();
})();
预加载是在页面加载时提前加载未使用的资源,以缩短后续请求的延迟。它可以在用户需要访问资源时,提供更快的响应时间。