分步解析js原生实现高性能懒加载
一个简单的高性能懒加载实例,为了节约 window.onscroll的次数 ,提高性能, 设计了函数节流和函数防抖两种模式。
1.简单懒加载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
img{
display: block;
max-height: 300px;
}
</style>
</head>
<body>
<div class="container">
<h1>懒加载页面</h1>
<img src="1.png" data-src='1.jpg' alt="">
<img src="1.png" data-src='2.jpg' alt="">
<img src="1.png" data-src='3.jpg' alt="">
<img src="1.png" data-src='4.jpg' alt="">
<img src="1.png" data-src='5.jpg' alt="">
<img src="1.png" data-src='6.jpg' alt="">
<img src="1.png" data-src='7.jpg' alt="">
<img src="1.png" data-src='8.jpg' alt="">
<img src="1.png" data-src='9.jpg' alt="">
</div>
</body>
</html>
<script>
var scrollTop = window.scrollY;
var imgs = Array.from(document.querySelectorAll('img'));
lazyLoad();
window.onscroll = () => {
scrollTop = window.scrollY;
lazyLoad();
}
function lazyLoad(){
imgs.forEach((item,index)=>{
if( item.offsetTop < window.innerHeight + scrollTop ){
console.log(item.offsetTop)
item.setAttribute('src',item.dataset.src)
}
})
}
</script>
这里有坑请注意!!!
如果复制上面的代码,首次加载进页面发现所有图片均已经加载完毕,没有实现懒加载的效果,因为函数调用时img.onload没有完成,img元素没有高度!!! 解决办法是在外层套一个window.onload
window.onload = function(){
lazyLoad();
}
2.函数节流throttle懒加载
高频滚动模式下, 每隔一段时间才会实现渲染,实现原理是加入一个开关变量, 控制每隔固定的一段时间,函数才可能被触发。
window.onload = function(){
var scrollTop = window.scrollY;
var imgs = Array.from(document.querySelectorAll('img'));
lazyLoad();
//函数节流模式
var canRun = true;
window.onscroll = () => {
if( !canRun ){
return
}
canRun = false;
setTimeout(()=>{
scrollTop = window.scrollY;
lazyLoad();
canRun = true;
},1000)
}
function lazyLoad(){
imgs.forEach((item,index)=>{
if( item.offsetTop < window.innerHeight + scrollTop ){
console.log(item.offsetTop)
item.setAttribute('src',item.dataset.src)
}
})
}
}
为了逻辑清晰 , 打包成函数调用:
window.onload = function(){
var scrollTop = window.scrollY;
var imgs = Array.from(document.querySelectorAll('img'));
lazyLoad();
let canRun = true;//开关变量用于函数节流
window.addEventListener('scroll',throttle(lazyLoad,500));
//定义懒加载函数 , 从上到下懒加载 , 从下到上也是懒加载
function lazyLoad(){
imgs.forEach((item,index)=>{
if( scrollTop===0 && item.dataset.src !== '' && item.offsetTop < window.innerHeight + scrollTop ){
alert()
item.setAttribute('src',item.dataset.src)
item.setAttribute('data-src','')
}else if( item.dataset.src !== '' && item.offsetTop < window.innerHeight + scrollTop && item.offsetTop > scrollTop ){
item.setAttribute('src',item.dataset.src)
item.setAttribute('data-src','')
}
})
}
//定义函数节流函数
function throttle(fun,delay){
return function(){
// fun();
if( !canRun ){
return
}
console.log('!!!')
canRun = false;
setTimeout(()=>{
scrollTop = window.scrollY;
fun(imgs);
canRun = true
},delay)
}
}
}
3.函数防抖debounce
原理是设置clearTimeout和setTimeout,的dalayTime控制一个事件如果频繁触发,将只会执行最近的一次… 可以用在用户注册时候的手机号码验证和邮箱验证。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。以下还是以页面元素滚动监听的例子
效果:一直滑动的时候,将不会有图片加载, 停下后300ms会加载
window.onload = function(){
var scrollTop = window.scrollY;
var imgs = Array.from(document.querySelectorAll('img'));
lazyLoad();
//函数防抖模式
var timer = null;
window.onscroll = () => {
clearTimeout(timer);
timer = setTimeout(()=>{
scrollTop = window.scrollY;
lazyLoad();
},300)
}
function lazyLoad(){
imgs.forEach((item,index)=>{
if( item.offsetTop < window.innerHeight + scrollTop ){
console.log(item.offsetTop)
item.setAttribute('src',item.dataset.src)
}
})
}
}
4.最终版 throttle + debounce , 完美懒加载
注意点: 在滚动条下拉状态下刷新页面, 页面实现更新渲染之后会立马触发滚动条事件,回到上一次页面的停留点,但是并不是从scrollTop为0的位置出发。
window.onload = function(){
var scrollTop = window.scrollY;
var imgs = Array.from(document.querySelectorAll('img'));
lazyLoad();
// 采用了节流函数
window.addEventListener('scroll',throttle(lazyLoad,500,1000));
function throttle(fun, delay, time) {
var timeout,
startTime = new Date();
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
// 如果达到了规定的触发时间间隔,触发 handler
console.log(curTime - startTime)
if (curTime - startTime >= time) {
fun();
startTime = curTime;
// 没达到触发间隔,重新设定定时器
} else {
timeout = setTimeout(fun, delay);
}
};
};
// 实际想绑定在 scroll 事件上的 handler
// 需要访问到imgs , scroll
function lazyLoad(){
scrollTop = window.scrollY;
imgs.forEach((item,index)=>{
if( scrollTop===0 && item.dataset.src !== '' && item.offsetTop < window.innerHeight + scrollTop ){
// alert()
item.setAttribute('src',item.dataset.src)
item.setAttribute('data-src','')
}else if( item.dataset.src !== '' && item.offsetTop < window.innerHeight + scrollTop && item.offsetTop > scrollTop ){
item.setAttribute('src',item.dataset.src)
item.setAttribute('data-src','')
}
})
}
}
链接:https://blog.csdn.net/weixin_40821790/article/details/78745796