图片懒加载的问题面试被问了几次,答了个大概,这次自己实现一下
原理
- data-src
<img src="./loading.png" data-src="./1.png">
data-src就是一个自己定义的属性,可以通过DOM.getAttribute(‘data-src’) 取到自定义的值。
2. data-src存放图片路径,src放loading的图片,然后根据el.getBoundingClientRect() 判断当前图片dom和可视区域的距离来决定是否加载图片。
实现
html部分
<div class="main" id="main">
<img src="./loading.jpg" data-src="./1.jpg" alt="">
<img src="./loading.jpg" data-src="./2.jpg" alt="">
<img src="./loading.jpg" data-src="./3.jpg" alt="">
<img src="./loading.jpg" data-src="./4.jpg" alt="">
<img src="./loading.jpg" data-src="./5.jpg" alt="">
<img src="./loading.jpg" data-src="./6.jpg" alt="">
<img src="./loading.jpg" data-src="./7.jpg" alt="">
<img src="./loading.jpg" data-src="./8.jpg" alt="">
<img src="./loading.jpg" data-src="./9.jpg" alt="">
<img src="./loading.jpg" data-src="./0.jpg" alt="">
</div>
- 获取图片DOM
let nodes = document.getElementsByTagName('img') // HTMLCollection(10)[img, img, ...]
let imgList = Array.apply(null, nodes) // 转为普通数组
- 写一个判断是否替换data-src的方法
getBoundingClientRect官方简介
function _isShow(el) {
let domRect = el.getBoundingClientRect() (https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect)
return domRect.top <= 20 && domRect.top >= 0
}
我判断的是当前图片距离可视区域上下距离决定是否显示。。。
3.再写一个加载图片的方法
function loadImg() {
for(leti = 0; i < imgList.length; i++) {
if (_isShow(imgList[i])) { // 上边的_isShow方法
imgList[i].src = imgList[i].getAttribute('data-src')
imgList.splice(i, 1)
i--
}
}
}
循环数组,判断是否需要加载图片,加载后将该图片从imgList中删除。
4. 最后写一个防抖,优化一下
function _debounce(fn, wait) {
let time = null
return function () {
clearTimeout(time)
time = setTimeout(() => {
fn.apply(this, arguments)
}, wait);
}
}
效果
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片懒加载</title>
<style>
.main{
width: 300px;
height: 200px;
border: 1px solid red;
overflow: auto;
}
img{
height: 180px;
width: 100px;
padding: 10px;
}
</style>
</head>
<body>
<div class="main" id="main">
<img src="./loading.jpg" data-src="./1.jpg" alt="">
<img src="./loading.jpg" data-src="./2.jpg" alt="">
<img src="./loading.jpg" data-src="./3.jpg" alt="">
<img src="./loading.jpg" data-src="./4.jpg" alt="">
<img src="./loading.jpg" data-src="./5.jpg" alt="">
<img src="./loading.jpg" data-src="./6.jpg" alt="">
<img src="./loading.jpg" data-src="./7.jpg" alt="">
<img src="./loading.jpg" data-src="./8.jpg" alt="">
<img src="./loading.jpg" data-src="./9.jpg" alt="">
<img src="./loading.jpg" data-src="./0.jpg" alt="">
</div>
<script>
let nodes = document.getElementsByTagName('img')
let imgList = Array.apply(null, nodes)
document.getElementById('main').addEventListener('scroll', () => {
_loadImg()
})
_loadImg = _debounce(loadImg, 50)
function loadImg() {
for(let i = 0; i < imgList.length; i++) {
if (_isShow(imgList[i])) {
imgList[i].src = imgList[i].getAttribute('data-src')
imgList.splice(i, 1)
i--
}
}
}
function _isShow(el) {
let domRect = el.getBoundingClientRect()
return domRect.top <= 50 && domRect.top >= 0
}
// 防抖
function _debounce(fn, wait) {
let time = null
return function () {
clearTimeout(time)
time = setTimeout(() => {
fn.apply(this, arguments)
}, wait);
}
}
</script>
</body>
</html>