为什么要懒加载
对页面加载速度影响最大的就是图片,一张普通的图片可以达到几M的大小,而代码也许就只有几十KB。当页面图片很多时,页面的加载速度缓慢,几S钟内页面没有加载完成,也许会失去很多的用户。
所以,对于图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。这样子对于页面加载性能上会有很大的提升,也提高了用户体验。
懒加载的原理
当图片不在可视区域内时,统一设置img
的src
为指定图片src='default.png'
,添加data-src
(自定义属性)属性指向真实图片url
<img src='default.png' data-src='httt://www.xxx.com/images/001.jpg'>
复制代码
监听scroll事件,当图片出现在可视区时,提取data-src
的值并赋给src
,加载真正图片
实现代码
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
img {
display: block;
margin-bottom: 50px;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="https://img1.baidu.com/it/u=3662100061,2823755293&fm=26&fmt=auto&gp=0.jpg" alt="">
<img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
<img src="default.jpg" data-src="https://img0.baidu.com/it/u=3290460621,176418012&fm=15&fmt=auto&gp=0.jpg" alt="">
<img src="default.jpg" data-src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdata.useit.com.cn%2Fuseitdata%2Fforum%2F201604%2F01%2F102512cgszscmpyq9xmd2i.jpg&refer=http%3A%2F%2Fdata.useit.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628316865&t=f24fed6c4dcc33aefdd3e836c863733f" alt="">
<img src="default.jpg" data-src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20180420%2Ff28943a3df704463abdd923478b40d08.png&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628316865&t=4b4eed09d9384fb51c56b79a238d7cde" alt="">
<script>
let sHeight = null
window.onscroll = lazyLoad
function lazyLoad(){
document.querySelectorAll("img").forEach(item=>{
sHeight = document.body.clientHeight
if( item.getBoundingClientRect().top < sHeight && item.attributes.src.value === "default.jpg" ){
item.attributes.src.value = item.attributes["data-src"].value
}
})
}
lazyLoad()
</script>
</body>
通过浏览器加载资源查看是否达到预期效果
还没完,lazyLode
与scorll
事件绑定会导致高频触发,这只会增加浏览器的压力,违背了我们的初衷,所以我们需要限制事件频率,改良代码如下
<script>
let sHeight = null
window.onscroll = debound(lazyLoad, 800)
//window.onscroll = debound(lazyLoad, 2000)
function lazyLoad(){
document.querySelectorAll("img").forEach(item=>{
sHeight = document.body.clientHeight
if( item.getBoundingClientRect().top < sHeight && item.attributes.src.value === "default.jpg" ){
item.attributes.src.value = item.attributes["data-src"].value
}
})
}
lazyLoad()
function debound(fn, wait) {
let timeOut = null
return function (){
clearTimeout(timeOut )
timeOut = setTimeout(()=>{
fn()
}, wait)
}
}
</script>
debounce
函数限制了lazyLoad
的触发频率,800ms等待时间内scroll时间再次触发则重置时间,术语叫防抖。这就完了?nonono!假设我们把wait
设的大点,2s,如果用户一直滑动滚动条,时间不断被重置,造成的效果是lazyLoad
一直不被执行,图片加载不出来,这是不能接受的,所以我们需要设置一个时间,超过该时间lazyLoad
必须执行一次,术语叫节流
,代码如下
function throttle(fn , wait, delay) {
let timeOut = null
let startTime = new Date()
let curtTime = null
return function (){
curtTime = new Date()
clearTimeout( timeOut )
if( curtTime - startTime > delay){
fn()
startTime = new Date()
}else {
timeOut = setTimeout(()=>{
fn()
startTime = new Date()
}, wait)
}
}
}