探究JS系列(一)图片懒加载

652 阅读2分钟

原理

将img标签src属性指向一张默认图片,然后定义data-src属性指向真实的图片。 图片要指定宽高

<img class="lazy-img" src="./imgs/lazy.png" data-src="./imgs/fact.png" alt/>

当载入页面时,监听页面滚动事件:当滚动到图片的可视区(或者还有某段固定距离)时,把图片的img标签的data-src属性值赋给src属性,从而发起请求将图片加载显示。

代码

在写代码前,需要了解各种高度。可参考这篇文章:scrollTop等元素距离


const lazyload = {
    data: {
        imgs: [], // 懒加载图片集
        startIndex: 0, // 懒加载开始位置
        visibleHeight: document.documentElement.clientHeight + 50, // 可见区域高度 + 提前加载距离
        scrollTop: 0, //滚动条距离顶部高度
        loadHeight: 0,
        during: 100, // 节流时间
        startTime: Date.now(),
        listener: null, // 滚动监听器
        timer: null // 节流监听器
    },
    // 图片懒加载
    lazyload() {
        this.data.scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        this.data.loadHeight = this.data.visibleHeight + this.data.scrollTop;
        console.log('滚动监听中...');
        //监听页面滚动事件
        for (let i = this.data.startIndex; i < this.data.imgs.length; i++) {
            console.log('查询中...' + this.data.imgs[i].scrollTop + ' , ' + this.data.loadHeight);
            if (this.data.imgs[i].offsetTop > this.data.loadHeight) {
                break;
            }
            this.data.imgs[i].src = this.data.imgs[i].getAttribute('data-src');
            console.log(this.data.imgs[i], '完成懒加载' + i);
            this.data.startIndex = i + 1;
            if (this.data.startIndex === this.data.imgs.length) {
                console.log('图片全部加载完毕,移除滚动监听');
                // 图片全部加载完毕,移除滚动监听
                window.removeEventListener('scroll', this.data.listener);
            }
        }
    },
    // 缓存中读取图片
    cacheload() {
        for (var i = 0; i < this.data.imgs.length; i++) {
            this.data.imgs[i].src = this.data.imgs[i].getAttribute('data-src');
        }
    },
    // 节流
    throttle() {
        return () => {
            clearTimeout(this.data.timer);
            let now = Date.now();
            if (now > this.data.startTime + this.data.during) {
                this.lazyload();
                this.data.startTime = now;
            } else {
                this.data.timer = setTimeout(() => {
                    this.lazyload();
                }, this.data.during);
            }
        };
    },
    // 初始化函数
    init() {
        this.data.imgs = document.querySelectorAll('.lazy-img');
        if (JSON.parse(sessionStorage.getItem('loaded'))) {
            // 二次加载,无需执行懒加载
            this.cacheload();
        } else {
            // 首次加载,需执行懒加载
            sessionStorage.setItem('loaded', true);
            this.lazyload();
            window.addEventListener('scroll', (this.data.listener = this.throttle.call(this)));
        }
    }
};
lazyload.init();

思考

  1. 第一次进入页面时图片使用懒加载,再次进入不发触发懒加载

优化: 使用session判断是否是首次加载页面,是否需要执行懒加载

  1. 如果直接将函数绑定在scroll事件上,当页面滚动时,函数会被高频触发,这非常影响浏览器的性能

使用函数节流来限制触发频率,优化性能 探究JS系列(二)节流与防抖

  1. 页面加载完成后,不等用户滚动页面。主动去请求懒加载图片资源。