js原生实现高性能懒加载(分步解析)

小弟不才,自己做了一个简单的懒加载,为了节约 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);
            // 如果达到了规定的触发时间间隔,触发 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','')
            }
        })
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_40821790/article/details/78745796
今日推荐