图片懒加载实现与深入的用户体验

462 阅读2分钟

图片懒加载

在网站开发中,经常有一些页面需要加载大量图片,所以会有大量图片请求,性能优化之一就有较少网络请求要求,所以为了减轻浏览器负担,我们需要根据用户可视区域视角,内的图片才发起请求,在网页末尾端底部的图片,用户是还看不到的,所以暂时没有必要网络请求;

懒加载优点

  • 减轻浏览器负担,让内存先完成必须的工作
  • 减少网络请求
  • 较少并行时大量流量

实现关键逻辑:

  • 可视区域高度 window.innerHeight
  • img到顶部高度 getBoundingClientRect().top
  • 观察或监听 img到顶部距离是否小于可视区高度
  • img添加data-src默认属性 不设置src属性
  • 可加载图片: 离顶部高度 < 窗口可视区
  • 不加载图片: 离顶部高度 > 窗口可视区

代码实现

  • 方案一
const images = document.querySelectorAll("img")

window.addEventListener("scroll", () => {
    images.forEach(img => {
        const imgTop = img.getBoundingClientRect().top
        // 图片距离顶部高度 小于 可视区域高度
        if (imgTop < window.innerHeight) {
            img.setAttribute('src', img.getAttribute('data-src'))
        }
    });
})
  • 缺点:每次滚动条的滚动,会触发大量的事件,如果页面需要加载很多内容就会导致任务的堆积,而且就算图片全部加载完了,但是还是会继续执行事件,及时做了判断删除代理 removeEventListener 但是又要IE的兼容判断,繁琐得不要不要

  • 推荐最优方案new IntersectionObserver() 浏览器提供的观察者构造器,除了Internet其他主流浏览器都支持 详细文档


  • 方案二(最佳案例)
const images = document.querySelectorAll("img")

// 创建一个观察者 观察元素每次 出现可视区域交叉时候(看到了和划走了交叉)
const observer = new IntersectionObserver((entries = []) => {
    // 回调函数会触发2次,1:目标元素出现时触发, 2:元素看不见了触发
    entries.forEach(item => {
        // 观察到元素出现在可视区域
        if (item.isIntersecting) {
            const img = item.target
            img.setAttribute('src', img.getAttribute('data-src'))
            // 任务完成 关闭观察
            observer.unobserve(img)
        }
    })
})

images.forEach(image => {
    // 遍历每个img元素,并放入观察
    observer.observe(image);
})

用户体验

  • 以上就是懒加载方案实现了,当然这里并未结束,为了更好用户体验,我们可以给图片加载时错误时 进行期间默认图片,加入loading...,error图片
  • 继续深入体验优化:图片加载异常后,放一个重新加载功能,用户点击后,重新请求备案的src地址。

推荐插件

  • v-lazy vue插件
  • react-lazyload react插件

最后感谢