• 开发中实现图片懒加载


    图片懒加载,即在图片出现在视口内或即将出现在视口内时再加载图片。图片懒加载可以分解为两个问题:

    • 如何判断图片在视口内
    • 如何控制加载图片

    计算图片位置 + 滚动事件 + DataSet API

    先设置一个临时的data属性的src占位

    <img data-src="./images/01.jfif">
    

    然后就可以下面的isShow()函数判断该图片是否在视口中,即元素相对顶点的值<=滚动的距离+窗口的高度 [ + 预留的加载距离]

    function isShow($node, preDistance) {
        return $node.offset().top <= $(window).height() + $(window).scrollTop() + preDistance;
    }
    

    当图片出现(或即将出现)在视口,就可以控制图片开始加载,这里使用datasetAPI

    function lazyload($imgs) {
        $imgs.each(function(idx, img) {
            if (img.src) return;
            if (isShow($(img), 100)) {
                img.src = img.dataset.src;
            }
        })
    }
    

    在页面加载的同时就要先调用一次lazyload()函数,让已经在视口中(首屏中)的图片开始加载,然后监听scroll事件,并在事件监听器中调用lazyload()函数。

    lazyload($imgs);
    
    window.onscroll = function (evt) {
        lazyload($imgs);
    }
    

    getBoundingClientRect + 防抖 + DataSet API

    这里引入Element.getBoundingClientRect()方法,此方法返回一个DOMRect对象,这个对象中提供了元素大小和相对于视口(左上角)的位置信息

    如此,就可以不通过jQuery来获取元素的位置了。

    function isShow(img, preDistance) {
        return img.getBoundingClientRect().top <= document.documentElement.clientHeight + preDistance;
    }
    

    同样的,在lazyload()函数中用for循环代替jQuery元素的each()方法。

    function lazyload(imgs) {
        for (let i = 0, len = imgs.length; i < len; i++) {
            const img = imgs[i];
            if (img.src) continue;
            if (isShow(img, 100)) {
                img.src = img.dataset.src;
            }
        }
    }
    

    由于滚动事件是高频事件,加个节流提高性能。一般使用lodash就够了。

    // 获取元素
    const imgs = document.querySelectorAll('img');
    // 首屏加载
    lazyload(imgs);
    
    function handleScroll() {
        lazyload(imgs);
    }
    
    window.onscroll = _.throttle(handleScroll, 136);
    

    IntersectionObserver API + DataSet API

    以上两种方法都是固定套路:计算位置,加载图片,节流。于是浏览器新增了一个三合一的API:IntersectionObserver(IE不支持)

    • IntersectionObserver是一个类,实例化时传入一个回调函数作为构造函数参数。
    • 这个回调函数接收一个changes参数,是一个对象数组,包含一系列变化对象。
    • changes数组中的某一个对象的isIntersecting属性为true时,表示被观察对象出现在视口中。这时可以写入图片加载程序,这里同样使用DataSet API
    • 图片加载程序完成后,使用observer.unobserve()方法取消订阅change.target对象,以防止重复加载。
    const observer = new IntersectionObserver(changes => {
        changes.forEach(change => {
            if (change.isIntersecting) {
                const item = change.target;
                item.src = item.dataset.src;
                observer.unobserve(item);
            }
        })
    });
    

    此对象实例化后,就可以使用observer.observe()方法订阅所有需要懒加载的图片

    const imgs = document.querySelectorAll('img');
    
    imgs.forEach(img => {
        observer.observe(img);
    })
    

    IntersectionObserver 除了给图片做懒加载外,还可以对单页应用资源做预加载。

    LazyLoading属性

    这应该是最简单的方式了,不过对前端而言,越简单代表兼容性越不好。
    同时,使用loading="lazy"后,并不是图片刚好进入视口时才加载,而是预留了一部分的加载距离。

    <img src="./images/01.jfif" loading="lazy">
    

    [参考资料] https://q.shanyue.tech/fe/html/1.html

  • 相关阅读:
    10000台不稳定机器如果做爬虫
    python 豆瓣高分电影爬虫
    恶意爬虫让机票价格暴涨 每年或致航空公司损失十多亿元
    python 豆瓣高分电影爬虫
    Python 爬虫保存图片
    你的爬虫票价价格暴涨
    10分钟教你利用Python网络爬虫获取穷游攻略
    10分钟教你利用Python网络爬虫获取穷游攻略
    SAP Cloud for Customer 如何直接消费S/4HANA API
    如何分辨 SAP Fiori Launchpad 里的真假 Fiori 应用
  • 原文地址:https://www.cnblogs.com/hycstar/p/14621268.html
Copyright © 2020-2023  润新知