小弟不才,自己做了一个简单的懒加载,为了节约 window.onscroll的次数 ,提高性能, 设计了函数节流和函数防抖两种模式 , 后面想到更好的方法会更新,也请各位朋友多多指点!! :D
废话不多说,直接亮代码~~
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);// 如果达到了规定的触发时间间隔,触发 handlerconsole.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','')}})}}