前端图片渲染性能优化与实践 — 图片懒加载

前言

对于图片量比较大的点上首页APP等,在打开商品展示页面的时候需要再加大量图片,在这种场景下如果直接全量加载,必然会造成页面性能消耗过大,白屏或者卡顿,用户体验非常糟糕,用户真的需要我们显示所有图片一起展示吗?其实并不是,用户看到的只是浏览器可视区域的内容。所以从这个情况我们可以做一些优化,只显示用户可视区域内的图片,当用户触发滚动的瞬间再去请求显示给用户

图片懒加载的实现:

  1. 给所有需要展示的 img 标签添加自定义属性: data-src ,同时不要设置 src 属性,data-src的值为图片url。

  2. 当页面加载完后,我们需要获取所有需要懒加载的图片的元素集合,判断是否在可视区域,如果是在可视区域的话,再重新设置元素的src属性值为真正图片的地址。

  3. 可视化区域的判断:是通过获取元素的getBoundingClientRect属性的top值和页面的clientHeight进行对比,如果top值小于clientHeight,则说明元素出现在可视区域之内。

  4. 当用户滚动窗口的时候,此时应该通过每个元素的BoundingClientRect属性来判断元素是否出现在可视区域内,如果在可视区域内,就渲染图片展示在可是区域内。

懒加载的实现:

<!-- 只在可视化区域内加载图片 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body> <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG"
        alt=""> <img style="width: 250px;height: 250px;background-color: grey; display: block;"
        data-src="./img/test01.PNG" alt=""> <img
        style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
</body>
<script>
    var viewHeight = document.documentElement.clientHeight; // 可视化区域的高度    
    var viewWidth = document.documentElement.clientWidth; // 可视化区域的宽度    
    function lazyload() { //获取所有要进行懒加载的图片        
        let eles = document.querySelectorAll('img[data-src]'); // 获取属性名中有data-src的        
        console.log('获取所有的信息', eles)
        Array.prototype.forEach.call(eles, function (item, index) {
            let rect;
            if (item.dataset.src === '') {
                return;
            }
            rect = item.getBoundingClientRect(); // 返回元素的大小及其相对于视口的位置            
            console.log('返回元素的大小及其相对于视口的位置', rect) //图片一进入可视区,动态加载            
            if (rect.bottom >= 0 && rect.top < viewHeight) {
                ! function () {
                    let img = new Image();
                    img.src = item.dataset.src;
                    img.onload = function () {
                        item.src = img.src;
                    }
                    item.removeAttribute('data-src');
                }();
            }
        })
    }
    lazyload();
</script>

</html>

上述代码中,我们已经初步完成图片懒加载,但是我们大家都知道,scroll这个事件,用户滚动鼠标就会触发很多次,这也会导致我们的性能急剧下降,所以这就引出了我们的混合体 防抖函数优化我们的性能:

function debounce(fn, gapTime) {
        let timer = null;
        return function () {
            if (timer) {
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(function () {
                fn();
            }, gapTime)
        }
    }

最后贴出完整代码:

<!-- 只在可视化区域内加载图片 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img id="img" style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
</body>
<script>
    var viewHeight = document.documentElement.clientHeight;  // 可视化区域的高度
    var viewWidth = document.documentElement.clientWidth; // 可视化区域的宽度
    console.log('可视化区域的高度', viewHeight)
    console.log('可视化区域的宽度', viewWidth)
    let imgDom = document.getElementById('img');
    console.log(window.getComputedStyle(imgDom, null).color);        // 用来取所有的

    function lazyload () {
        //获取所有要进行懒加载的图片
        let eles = document.querySelectorAll('img[data-src]'); // 获取属性名中有data-src的
        console.log('获取所有的信息', eles)
        Array.prototype.forEach.call(eles, function(item, index) {
            let rect;
            if(item.dataset.src === '') {
                return;
            }

            rect = item.getBoundingClientRect();  // 返回元素的大小及其相对于视口的位置
            console.log('返回元素的大小及其相对于视口的位置', rect)

            //图片一进入可视区,动态加载
            if(rect.bottom >= 0 && rect.top < viewHeight) {
                !function () {
                    let img = new Image();
                    img.src = item.dataset.src;
                    img.onload = function () {
                        item.src = img.src;
                    }
                    item.removeAttribute('data-src');
                }();
            }
        })
    }
    lazyload();

    // 添加滚动事件触发图片加载
    document.addEventListener('scroll', debounce(lazyload, 500), false);

    // 通过函数防抖来持续优化:
    function debounce(fn, gapTime) {
        let timer = null;
        return function() {
            if(timer) {
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(function() {
                fn();
            }, gapTime)
        }
    }
 
</script>
</html>

掘金链接:

  • https://juejin.cn/post/6977945074885722126
  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值