likes
comments
collection
share

性能优化之图片懒加载使用vue-lazyload或IntersectionObserver观察检测者

作者站长头像
站长
· 阅读数 19

懒加载问题描述

  • 网站上有大量图片,若一次性直接请求所有的图片资源,很显然时间等待过长,浪费资源。
  • 所以我们就需要需要给图片做一个懒加载,即:等看到图片,或者快看到图片时,才去加载
  • 就像移动端下拉加载一样
  • 也有种数据分页的感觉

懒加载问题解决思路

  • 第一步,初始时,先给图片一个loading.gif作为imgsrc的值,使其显示加载中,如:img.src = loading.gif
  • 第二步,判断元素是否进入视口,是否(即将)能看到,再将imgsrc的值,替换为真正的需求请求地址的值
  • 第三步,当imgsrc的值的时候,就会立刻发请求,请求服务器的资源,请求成功了,就成功了,就达到我们想要的效果
  • 第四步,兜错,若图片加载请求失败的话,再将imgsrc替换成一张加载失败错误的图片src即可

这里有两个重点,大家需要注意:

问题一:如何判断元素是否进入可视区域?

问题二:如何判断图片加载成功或失败了?

这两个问题的答案后文会提到,大家继续往下阅读

图片懒加载效果

最终实现的就是这样的效果

性能优化之图片懒加载使用vue-lazyload或IntersectionObserver观察检测者

也可以去笔者的个人网站上,看效果图:ashuai.work:8888/#/imgLazylo…

解决方案

  • 或者使用现有的插件
  • 或者自己写一个

方案一 插件就是好!vue-lazyload

推荐使用vue-lazyload插件各方面都很优化,官方地址:www.npmjs.com/package/vue…

使用步骤,这里笔者就不赘述了,上述的效果图,也是通过这个vue-lazyload插件实现的,对应代码,在笔者的GitHub仓库中:github.com/shuirongshu…

方案二 自己手写一个自定义指令v-lazyload

写一个自定义指令,便于逻辑复用

如何判断元素是否进入视口了?

麻烦一些的方案:监听拥有滚动条的scroll事件,去计算元素距离拥有滚动条的位置,这里笔者总结了一个公式:

  • 滚动距离出现 = .target距顶部高度 - .scrollBox距顶部高度 - .scrollBox自身高度
  • 边界值 = 目标元素距顶部高度 - 滚动盒子容器距顶部高度 - 滚动盒子容器自身高度

相关代码案例,请看笔者的这篇文章:juejin.cn/post/720178…

使用IntersectionObserver类构造函数,去判断元素是否进入视口

IntersectionObserver是一个非常强大的api,可以观测很多东西的变化,very good,在浏览器版本不断更新迭代的现在,其兼容性已经非常不错了,大家可以放心使用。

关于IntersectionObserver的语法,笔者不赘述了,咱们直接上自定义指令代码

自定义指令代码

// let loadimage = "http://ashuai.work:10000/imgGifSrc/loading.gif" // 服务器加载中图片
// let errorimage = "http://ashuai.work:10000/imgGifSrc/error.gif" // 服务器加载中图片

let loadimage = require('../../assets/imgLazyload/loading.gif')  // 本地加载中图片
let errorimage = require('../../assets/imgLazyload/error.gif')  // 本地加载失败图片

export default {
    inserted(el, binding, vnode) { 
        // 1. 先让图片显示加载中...
        el.src = loadimage.default 
        // 2. 实例化一个:观察检测者
        const observer = new IntersectionObserver((entries) => {
            // 4. 在观察监测者的对应执行函数中获取到isIntersecting属性(是否交叉)
            let isIntersecting = entries[0].isIntersecting 
            // 5. 如果交叉了,就让其去加载对应src的真正的地址
            if (isIntersecting) { 
                el.src = binding.value
                // 6. 加载成功就不用管它
                el.onload = (res) => console.log('加载成功', res); 
                // 7. 加载失败了就去做一个错误图片的占位
                el.onerror = (err) => {
                    console.log('加载失败', err);
                    el.src = errorimage.default
                }
                // 8. 无论加载成功或失败,都停止观察任务了
                observer.unobserve(el)
            }
        })
        // 3. 让这个观察检测者去观察对应img标签图片
        observer.observe(el)
    },
}

使用代码

使用的话,很简单,直接:

<img class='imgLazy' v-lazyload="'http://ashuai.work:10000/imgSrc/doupo.png'" />
<img class='imgLazy' v-lazyload="'http://ashuai.work:10000/imgSrc/douluo.png'" />
<img class='imgLazy' v-lazyload="'http://ashuai.work:10000/imgSrc/tunshi.png'" />

注意使用自定义指令别忘了要注册哦

最后,烦请各位道友去笔者的GitHub仓库看看,如果觉得对您有一点点帮助的话,不妨不吝star😀

自定义指令的完整代码也在笔者的GitHub仓库中哦