前端基础-图片懒加载

113 阅读1分钟

懒加载实现过程

补上之前的笔记。
全文内容全部来自参考文章juejin.cn/post/684490…

基础

懒加载,首先要确定用户可见区域
网页可见区域宽: document.body.clientWidth;
网页可见区域高: document.body.clientHeight;

网页可见区域宽: document.body.offsetWidth (包括边线的宽);
网页可见区域高: document.body.offsetHeight (包括边线的宽);
网页正文全文宽: document.body.scrollWidth;
网页正文全文高: document.body.scrollHeight;
网页被卷去的高: document.body.scrollTop;
网页被卷去的左: document.body.scrollLeft;
浏览器距离屏幕上: window.screenTop;
浏览器距离屏幕左: window.screenLeft;
屏幕分辨率的高: window.screen.height;
屏幕分辨率的宽: window.screen.width;
屏幕可用工作区高度: window.screen.availHeight;

选用document.body.clientWidth 与 document.body.clientHeight.

当图片进入可见区域(图片距离顶部的top < 整个文档的 clientHeight + scrollTop):图片加载真实地址;

核心代码

<script>
    var num = document.getElementsByTagName('img').length; //图片个数
    var img = document.getElementsByTagName("img"); //图片元素数组
    
    var n = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历

    lazyload(); //页面载入完毕加载可是区域内的图片

    window.onscroll = lazyload;

    function lazyload() { //监听页面滚动事件
        var seeHeight = document.documentElement.clientHeight; //可见区域高度
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滚动条距离顶部高度
        for (var i = n; i < num; i++) {
            if (img[i].offsetTop < seeHeight + scrollTop) { //如果图片距离顶部body的距离小于可见高度+滚动距离
            // 这里的offsetTop可改为getBoundingClientRect().top
                if (img[i].getAttribute("src") == "default.jpg") { //如果出现在可见区域的图片指向默认图片
                    img[i].src = img[i].getAttribute("data-src");  //则替换原本的src变为真实地址
                }
                n = i + 1;  //更换加载到的图片位置
            }
        }
    }
</script>

以下来自定义: Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。

如果是标准盒子模型,元素的尺寸等于width/height + padding + border-width的总和。如果box-sizing: border-box,元素的的尺寸等于 width/height。

返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有left, top, right, bottom, x, y, width, 和 height这几个以像素为单位的只读属性用于描述整个边框。除了width 和 height 以外的属性是相对于视图窗口的左上角来计算的。
Element.getBoundingClientRect()返回参数示意图
developer.mozilla.org/zh-CN/docs/…

优化

问题1: 函数绑定在scroll事件上,当页面滚动时,函数会被高频触发,非常影响浏览器的性能。
使用节流函数优化:只允许一个函数在N秒内执行一次。
问题2:判断元素是否可见
传统方法如上述,getBoundingClientRect().top或者offsetTop。
该可以利用高级特性Intersection Observer来判断元素是否可见。
参考链接: 作者:大雄没了哆啦A梦 链接:juejin.cn/post/684490…

if ("IntersectionObserver" in window) {        
    let lazyImageObserver = new IntersectionObserver((entries, observer) => {          
        entries.forEach((entry, index) => {            
            // 如果元素可见            
            if (entry.intersectionRatio > 0) {              
                let lazyImage = entry.target              
                lazyImage.src = lazyImage.dataset.src              
                lazyImage.classList.remove("lazy-image")              
                lazyImageObserver.unobserve(lazyImage)              
                // this.lazyImages.splice(index, 1)            
            }          
        })        
    })        
    this.lazyImages.forEach(function(lazyImage) {          
        lazyImageObserver.observe(lazyImage);        
    })      
}