图片懒加载

前言

本文主要围绕一下主题进行阐述

  1. 为什么要进行图片懒加载
  2. 什么场景下需要进行图片懒加载
  3. 如何实现懒加载
    • 传统实现
    • 优化方案

介绍

在一些图片密集型网站中,一次加载过多图片会导致请求阻塞。通过图片懒加载可以让一些不可视的图片不去加载,避免一次性加载过多的图片导致请求阻塞(浏览器一般对同一域名下的并发请求的连接数有限制),这样就可以提高网站的加载速度,提高用户体验。

实现

思路/传统实现方案:

第一步:

  • 将不需要展示(需要懒加载)的img标签src设置缩略图/不设置src
  • 自定义一个属性存储src
  • 定义一个类名
    • 作用
      • 表示该图片是需要懒加载
      • 可以为这个类名设置背景图 作为未加载前的过渡
<img src="https://tb1.bdstatic.com/tb/cms/liveshow/ent_slid2.jpg" class="lazy-image"/> 
// css部分 
.lazy-image { 
    background: url('../img/loading.gif') no-repeat center; 
} 
复制代码

第二步
获取所有需要懒加载的图片元素集合,判断是否在可视区内 是的话设置元素src为真正的图片地址

inViewShow() {   
    //所有需要懒加载的图片 元素集合
    let imageElements = Array.prototype.slice.call(document.querySelectorAll('.lazy-image'))    
    let len = imageElements.length     
    for(let i = 0; i < len; i++) {         
        let imageElement = imageElements[i]        
        const rect = imageElement.getBoundingClientRect() 
        // 出现在视野的时候加载图片         
        if(rect.top < document.documentElement.clientHeight) {             
            imageElement.src = imageElement.data-src 
            // 移除掉已经显示的             
            imageElements.splice(i, 1)             
            len--             
            i--         
        }     
    } 
}
复制代码

ps getBoundingClientRect用于获取某个元素相对于视窗的位置集合 {top,bottom,left,right}

image.png
第三步
当用户滚动窗口的时候,遍历所有需要懒加载的元素,通过每个元素的BoundingClientRect属性来判断元素是否出现在可视区域内

document.addEventListener(‘scroll’, inViewShow)

缺点:
监听scroll事件,调用元素的getBoundingClientRect()方法判断是否在视口内,事件密集发生计算量大,容易造成性能问题。虽然可以通过节流函数来提高性能,但是还是会造成性能的浪费

优化方案

IntersectionObserver(交叉观察器) API 自动‘观察’元素是否可见

// 用法
var io = new IntersectionObserver(callback, option);   call- 回调 opt-配置对象  
 // 开始观察  
 io.observe(document.getElementById('example'));   ps 观察多个节点则调用多次
 // 停止观察  
 io.unobserve(element);  
 // 关闭观察器  
 io.disconnect();
复制代码

代码实现

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);        
   })      
}
复制代码

IntersectionObserver API 参考文档

www.ruanyifeng.com/blog/2016/1…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享