图片懒加载处理,了解一下?

最近在给公司写微商城,但是写完后单页的商品太多,导致图片加载很慢,而且我发现公司给服务器域名限制了单个IP器访问速度最高只有500K/s,面对这种情况,只好对图片进行懒加载处理了。

接下来要给大家到来的是前端图片懒加载的实现和思路,主要分两种:纵向的和横向的。

  • 不管是纵向的还是横向图片懒加载实现的思路都是一样
  • 首先在第一次渲染列表图片时,不要把图片路径直接赋值给src(不然的话整个页面的图片都会一起加载)
  • 然后在img标签中自定义一个属性值,我这里用src-url表示,然后将图片路径先赋值给src-url(此时页面并不会真正显示图片)
  • 然后监听页面滚动,判断图片外层div或者内层src标签都可以,当其出现在页面时将src-url的图片路径赋值给img标签的src属性(这时图片会加载渲染)
  • 然后把多余的自定义属性值src-url给删掉
  • 这样我们就控制了只有在设备窗口中出现的图片才加载显示的这么一个效果

▼纵向图片懒加载

GIF效果图:
在这里插入图片描述

整个HTML

纵向的还是比较好实现的,直接监听window层的onscroll就好了,获取每一个图片距离窗口顶部的距离也会很容易,也不用考虑多个滚动条的情况。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>纵向懒加载图片</title>
</head>

<style>
    body {
        margin: 0;
    }

    .block .item {
        width: 100vw;
        height: 100vw;
    }

    .item img {
        width: 100vw;
        height: 100vw;
    }
</style>

<body>
    <main>
        <div class="block" id="blick-id">
            <!-- <div class="item">
                <img src="" alt="">
            </div> -->
        </div>
    </main>
</body>
<!-- <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> -->
<script>
    var imgArr = ['http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3X8RoF22*mTXfJ3*RNuBlDKADJ1uOLA7MGzFp8BJJXnqeNhEXGt9UcyseKRjTRL3g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAxNbk8AOn2*a26dMBu9JTc5ZMjUoOP8CXSWklFFu3wNX1doPdvuRbT1XP*LngYIcYQ!!/b&bo=qAKoAqgCqAIRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAycZuvsrYM89XrUpvXk.BK7uk48c7uH5PB.O54*yiHLP2DcqIniegFyShf51OvTodw!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA7XyxBYj1ChXgmpm2TPBJ9Qwg7Pg.b85HrbKUQMCkvQPZe8.CKMUzq4gadEk6ZLK7g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2FzxFGTwkwju8grAh*GGjv1BSvZN3Ob9ZKplkXdZtK0dp7dwORVtLeFlZYYpPVWLA!!/b&bo=0ALQAtAC0AIRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3PQtUyBpTU*8PxS83qy6uNvksCAXfA*BjDhPE*k8S48m6I7.tvBznnNyMVpMUe2lA!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA1E320PXRp5qlcLil8TkwsUJIBXnUyjiBKUyIvQnmY87Gx3eBsgtJlhJ5m4P8G12ww!!/b&bo=NgE2ATYBNgERCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2mIh303WaCbhJsTAaw4ebe6WoKyO4SX*lp0lb3pwbXgfdMqCXj5VFP3D.dRrq9UZg!!/b&bo=9AH0AfQB9AERCT4!&rf=viewer_4',
    ]
    //自定义字符串,拼接列表数据
    var itemStr = '';
    //自定义属性值src-url,用于暂存图片路径
    imgArr.forEach((e) => {
        itemStr += `<div class="item">
                        <img src-url="${e}" alt="">
                    </div>`
    })
    //将拼接后的字符串渲染到列表中
    document.getElementById('blick-id').innerHTML = itemStr;

    window.onload = () => {
        // 获取图片列表
        var imgList = document.getElementsByClassName('block')[0].children;
        // console.log(imgList);
        // 初次渲染图片
        lazyLoad(imgList)
        // 二次监听滚动渲染图片
        window.onscroll = function () {
            lazyLoad(imgList);
        };
    }

    //封装懒加载图片方法
    function lazyLoad(imgList) {
        //获取屏幕高度
        var viewHeight = window.innerHeight;
        // console.log(viewHeight)
        //获取纵向滚动的值
        var scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;
        // console.log(scrollHeight)
        for (var i = 0; i < imgList.length; i++) {
            // console.log(imgList[i].offsetTop)
            //判断,当图片出现在页面时,
            //imgList[i].offsetTop表示图片外层div距离设备窗口顶部的距离
            if ((viewHeight + scrollHeight) >= imgList[i].offsetTop) {
                //设置立即调用函数
                (function (i) {
                    // 设置延时模拟图片加载缓慢的情况,实际项目中去求就好
                    setTimeout(function () {
                        // console.log(imgList[0].children[0]);
                        // console.log(imgList[i].children[0].getAttribute('src'));
                        //当前图片的节点
                        var imgNode = imgList[i].children[0];
                        //判断,如果图片的路径是空的,就对其进行赋值,且删除多余的自定义属性
                        if (imgNode.getAttribute('src') == null) {
                            imgNode.setAttribute('src', imgNode.getAttribute('src-url'));
                            imgNode.removeAttribute('src-url');
                        }
                    }, 1000)
                })(i)
            }
        }
    }
</script>

</html>

▼横向图片懒加载

GIF效果图:
在这里插入图片描述

整个HTML

横向的考虑因数会比较多,因为一般横向展示物品不单只是一横排的,所以面对多人运动,呸,多排展示时,我们要分别对每一横排的滚动进行处理。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>横向懒加载图片</title>
</head>

<style>
    body {
        margin: 0;
    }

    .module .title {
        text-align: center;
        background-color: orange;
        color: white;
    }

    .block {
        display: flex;
        overflow-x: auto;
        overflow-y: hidden;
    }

    .block .item {
        display: flex;
        width: 50vw;
        height: 50vw;
    }

    .item img {
        width: 50vw;
        height: 50vw;
    }
</style>

<body>
    <main>
        <div class="module" id="module-id">
            <!-- <div class="row">
                <div class="title"></div>
                <div class="block">
                    <div class="item">
                        <img src="" alt="">
                    </div>
                </div>
            </div> -->
        </div>
    </main>
</body>
<!-- <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> -->
<script>
    var imgObj = [
        {
            title: '板块一',
            imgArr: ['http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3X8RoF22*mTXfJ3*RNuBlDKADJ1uOLA7MGzFp8BJJXnqeNhEXGt9UcyseKRjTRL3g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAxNbk8AOn2*a26dMBu9JTc5ZMjUoOP8CXSWklFFu3wNX1doPdvuRbT1XP*LngYIcYQ!!/b&bo=qAKoAqgCqAIRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAycZuvsrYM89XrUpvXk.BK7uk48c7uH5PB.O54*yiHLP2DcqIniegFyShf51OvTodw!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA7XyxBYj1ChXgmpm2TPBJ9Qwg7Pg.b85HrbKUQMCkvQPZe8.CKMUzq4gadEk6ZLK7g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2FzxFGTwkwju8grAh*GGjv1BSvZN3Ob9ZKplkXdZtK0dp7dwORVtLeFlZYYpPVWLA!!/b&bo=0ALQAtAC0AIRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3PQtUyBpTU*8PxS83qy6uNvksCAXfA*BjDhPE*k8S48m6I7.tvBznnNyMVpMUe2lA!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA1E320PXRp5qlcLil8TkwsUJIBXnUyjiBKUyIvQnmY87Gx3eBsgtJlhJ5m4P8G12ww!!/b&bo=NgE2ATYBNgERCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2mIh303WaCbhJsTAaw4ebe6WoKyO4SX*lp0lb3pwbXgfdMqCXj5VFP3D.dRrq9UZg!!/b&bo=9AH0AfQB9AERCT4!&rf=viewer_4',
            ]
        },
        {
            title: '板块二',
            imgArr: ['http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2mIh303WaCbhJsTAaw4ebe6WoKyO4SX*lp0lb3pwbXgfdMqCXj5VFP3D.dRrq9UZg!!/b&bo=9AH0AfQB9AERCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA1E320PXRp5qlcLil8TkwsUJIBXnUyjiBKUyIvQnmY87Gx3eBsgtJlhJ5m4P8G12ww!!/b&bo=NgE2ATYBNgERCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3PQtUyBpTU*8PxS83qy6uNvksCAXfA*BjDhPE*k8S48m6I7.tvBznnNyMVpMUe2lA!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2FzxFGTwkwju8grAh*GGjv1BSvZN3Ob9ZKplkXdZtK0dp7dwORVtLeFlZYYpPVWLA!!/b&bo=0ALQAtAC0AIRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA7XyxBYj1ChXgmpm2TPBJ9Qwg7Pg.b85HrbKUQMCkvQPZe8.CKMUzq4gadEk6ZLK7g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAycZuvsrYM89XrUpvXk.BK7uk48c7uH5PB.O54*yiHLP2DcqIniegFyShf51OvTodw!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAxNbk8AOn2*a26dMBu9JTc5ZMjUoOP8CXSWklFFu3wNX1doPdvuRbT1XP*LngYIcYQ!!/b&bo=qAKoAqgCqAIRCT4!&rf=viewer_4',
                'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3X8RoF22*mTXfJ3*RNuBlDKADJ1uOLA7MGzFp8BJJXnqeNhEXGt9UcyseKRjTRL3g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
            ]
        },
    ]
    //自定义字符串,拼接列表数据
    var moduleStr = '';
    //自定义属性值src-url,用于暂存图片路径
    imgObj.forEach((element, index) => {
        moduleStr +=
            `<div class="row">
                <div class="title">${element.title}</div>
                <div class="block" id="block${index}">
                 ${element.imgArr.map((e) => {
                return `<div class="item">
                            <img src-url="${e}" alt="">
                        </div>`}).join('')}
                </div>
            </div>`
    })
    //将拼接后的字符串渲染到列表中
    document.getElementById('module-id').innerHTML = moduleStr;

    window.onload = () => {
        //全部板块的节点
        var rowLists = document.getElementsByClassName(`module`)[0].children;
        // console.log(rowLists)
        lazyLoad(rowLists);
    }

    //封装懒加载图片方法
    function lazyLoad(rowLists) {
        //获取可视高度(屏幕高度)
        var viewWidth = window.innerWidth;
        /*注意,如果这里用var定义i,需要再包裹一层立即调用函数*/
        for (let i = 0; i < imgObj.length; i++) {
            //设置立即调用函数
            // (function (i) {
            // console.log(imgList)
            //封装加载每一个商品的方法
            function lazyLoadItem(e) {
                //滚动条距离窗口左侧的距离
                var scrollLeft = null;
                //判断,如果e等于空,说明是第一次渲染页面
                if (e == '') {
                    scrollLeft = 0;
                } else {
                    scrollLeft = e.target.scrollLeft;
                }
                for (let n = 0; n < imgObj[i].imgArr.length; n++) {
                    // console.log(viewWidth + scrollLeft)
                    // console.log(viewWidth / 2 * n)
                    //每一个商品图片外层div距离设备窗口左边的距离
                    var offsetLeft = rowLists[i].children[1].children[n].offsetLeft;
                    // console.log(offsetLeft)
                    if (viewWidth + scrollLeft > offsetLeft) {
                        //设置立即调用函数
                        (function (n) {
                            // 设置延时模拟图片加载缓慢的情况,实际项目中去求就好
                            setTimeout(function () {
                                // 当前商品图片的路径
                                var itemImg = rowLists[i].children[1].children[n].children[0];
                                // console.log(itemImg)
                                //判断,如果图片的路径是空的,就对其进行赋值,且删除多余的自定义属性
                                if (itemImg.src == '') {
                                    //获取真的图片路径
                                    var goodsSrc = itemImg.getAttribute('src-url');
                                    // 替换设置图片
                                    itemImg.setAttribute('src', goodsSrc);
                                    //清理掉原来的属性
                                    itemImg.removeAttribute('src-url');
                                }
                            }, 1000)
                        })(n)
                    }
                }
            }
            // 初次渲染图片
            lazyLoadItem('');
            //监听不同滑块的滚动
            document.getElementById(`block${i}`).addEventListener("scroll", function (e) {
                // console.log(e)
                // 二次渲染图片
                lazyLoadItem(e);
            })
            // })(i)
        }
    }

</script>

</html>
关于性能问题

细心的同学应该会发现一个问题,那就是每次监听到滚动变化时都会执行lazyLoad懒加载方法,然而你滑动一次屏幕可能触发了几十次这个方法,所以非常消耗性能,可能会出现滑动时有卡顿的现象。我在网上找了一些滚动停止触发的事例都不怎么理想(貌似都是用setTimeout执行方法,每次监听时都清理clearTimeout计时器,然后用scrollTop来判断执行前后是否相等,相等说明停止了),最后我在菜鸟教程jQuery Mobile 滚屏事件中找到了不错的解决方案,可以参考一下面这个例子

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jquery.mobile优化版纵向懒加载图片</title>
    <!-- 引入jquery全家桶 -->
    <link rel="stylesheet" href="https://apps.bdimg.com/libs/jquerymobile/1.4.5/jquery.mobile-1.4.5.min.css">
    <script src="https://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="https://apps.bdimg.com/libs/jquerymobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>

<style>
    body {
        margin: 0;
    }

    .block .item {
        width: 100vw;
        height: 100vw;
    }

    .item img {
        width: 100vw;
        height: 100vw;
    }
</style>

<body>
    <main>
        <div class="block" id="blick-id"></div>
    </main>
</body>
<script>
    var imgArr = ['http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3X8RoF22*mTXfJ3*RNuBlDKADJ1uOLA7MGzFp8BJJXnqeNhEXGt9UcyseKRjTRL3g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAxNbk8AOn2*a26dMBu9JTc5ZMjUoOP8CXSWklFFu3wNX1doPdvuRbT1XP*LngYIcYQ!!/b&bo=qAKoAqgCqAIRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBAycZuvsrYM89XrUpvXk.BK7uk48c7uH5PB.O54*yiHLP2DcqIniegFyShf51OvTodw!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA7XyxBYj1ChXgmpm2TPBJ9Qwg7Pg.b85HrbKUQMCkvQPZe8.CKMUzq4gadEk6ZLK7g!!/b&bo=LAEsASwBLAEDCSw!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2FzxFGTwkwju8grAh*GGjv1BSvZN3Ob9ZKplkXdZtK0dp7dwORVtLeFlZYYpPVWLA!!/b&bo=0ALQAtAC0AIRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA3PQtUyBpTU*8PxS83qy6uNvksCAXfA*BjDhPE*k8S48m6I7.tvBznnNyMVpMUe2lA!!/b&bo=IAMgAyADIAMRCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA1E320PXRp5qlcLil8TkwsUJIBXnUyjiBKUyIvQnmY87Gx3eBsgtJlhJ5m4P8G12ww!!/b&bo=NgE2ATYBNgERCT4!&rf=viewer_4',
        'http://photogz.photo.store.qq.com/psc?/V14ZaBeY27gVgy/BbSbWrmEw8nJ9LYcvxlBA2mIh303WaCbhJsTAaw4ebe6WoKyO4SX*lp0lb3pwbXgfdMqCXj5VFP3D.dRrq9UZg!!/b&bo=9AH0AfQB9AERCT4!&rf=viewer_4',
    ]
    var itemStr = '';
    imgArr.forEach((e) => {
        itemStr += `<div class="item">
                        <img src-url="${e}" alt="">
                    </div>`
    })
    document.getElementById('blick-id').innerHTML = itemStr;
    window.onload = () => {
        var imgList = document.getElementsByClassName('block')[0].children;
        lazyLoad(imgList)
        //在这里用jquery.mobile的scrollstop处理监听结束
        $(document).on("scrollstop", function () {
            // alert("停止滚动!");
            console.log("停止滚动!")
            lazyLoad(imgList);
        });
    }
    function lazyLoad(imgList) {
        var viewHeight = window.innerHeight;
        var scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;
        for (var i = 0; i < imgList.length; i++) {
            if ((viewHeight + scrollHeight) >= imgList[i].offsetTop) {
                (function (i) {
                    setTimeout(function () {
                        var imgNode = imgList[i].children[0];
                        if (imgNode.getAttribute('src') == null) {
                            imgNode.setAttribute('src', imgNode.getAttribute('src-url'));
                            imgNode.removeAttribute('src-url');
                        }
                    }, 1000)
                })(i)
            }
        }
    }
</script>

</html>

最后呢,其实在for循环输出列表时可以先赋值一张伪图(也就是加载图片中gif类型的轻量级图片)给img标签的src,然后
在setAttribute图片替换这一步中用onload监听真的图片加载完了再把url赋值给src,这样就不会产生图片一段一段加载的感觉,这个看个人的项目需求吧。加油同志们,奥利给!

奥利给释义:
作为感叹词,包含了赞美、加油打气等多种感情色彩。

白嫖罚多人运动,请自重










不要误会

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章