最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用IntersectionObserver优化图片加载

    正文概述 掘金(智云健康大前端团队)   2021-01-29   390

    作者:maxin,未经授权禁止转载。

    前言

    工作中经常通过判断元素是否进入视口,一般有三种方式进行判断

    1. el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
    2. el.getBoundingClientRect().top <= viewPortHeight
    3. intersectionRatio > 0 && intersectionRatio <= 1
    

    根据元素与视口是否相交,可以进行吸顶、吸底、曝光上报、列表加载更多、图片懒加载等操作。

    问题

    前面两种需要通过监听scroll事件,为了防止频繁触发,需要做防抖处理。

    用户体验

    • 当元素进入视口时,总是需要延迟一定时间才能执行判断逻辑。

    性能

    • 在主线程上运行,因此频繁触发、调用会造成性能问题
    • 无论是否触发相交,滚动结束后都会进行判断
    • 获取srollTop的值和getBoundingClientRect方法都会导致回流
    • 滚动事件会绑定多个事件处理函数,阻塞UI渲染

    IntersectionObserver

    当目标元素和根元素相交或失交,并且当前 tick 期间没有任务运行时,回调函数就会被执行

    构造函数

    let observer = new IntersectionObserver(callback, options);
    

    callback

    每个entry描述一个观察到的目标元素的交集变化

    使用IntersectionObserver优化图片加载

    let callback = (entries, observer) => {
      entries.forEach(entry => {
        // entry.boundingClientRect
        // 目标元素的区域信息,getBoundingClientRect()的返回值
        
        // entry.intersectionRatio
        // 目标元素的可见比例
        
        // entry.intersectionRect
        // 目标元素与根元素交叉的区域信息
        
        // entry.isIntersecting
        // 目标元素是否进入根元素区域
        
        // entry.rootBounds
        // 根元素的矩形区域信息
        
        // entry.target
        // 被观察dom节点
        
        // entry.time
        // 相交发生时距离页面打开时的毫秒数
      });
    };
    

    options

    • root 根元素,不指定默认为视窗
    • rootMargin 根元素的外边距
    • threshold 目标元素与根元素相交比例达到该值触发回调

    实例方法

    • observe 开始监听一个目标元素(target),target必须是root的后代
    • unobserve 停止监听一个目标元素
    • takeRecords 返回所有监听的目标元素集合
    • disconnect 停止所有监听

    参考

    MDN Web Docs - Intersection Observer API

    vue directive优化懒加载

    步骤

    防止直接加载图像,先把图片地址存放在data-src上

    <img
      class="image-item"
      :src="imageUrl"
      v-lazyload
    />
    

    LazyLoadDirective.js

    export default {
      // hookFunction 当绑定元素插入父节点时调用
      insert(el) {
        function loadImage() {
          el.addEventListener('load', () => {
            // 加载完成后延迟添加class可以实现淡入动画
            setTimeout(() => {
              el.classList.add('loaded')
            }, 100);
          });
    
          // 加载 data-url 的图片地址
          el.src = el.dataset.url;
        }
    
        function handleIntersect(entries, observer) {
          entries.forEach(entry => {
            if (!entry.isIntersecting) {
              return;
            } else {
              // 绑定元素进入视口后触发加载图片
              loadImage();
              // 并停止观察可见性变化, 防止再次加载图像。
              observer.unobserve(el);
            }
          });
        }
    
        function createObserver() {
          const options = {
            root: null,
            threshold: '0'
          };
    
          const observer = new IntersectionObserver(handleIntersect, options);
    
          // 订阅观察当前绑定图片元素
          observer.observe(el);
        }
        
        createObserver();
      }
    }
    

    思考

    注册指令

    // main.js 全局注册
    import Vue from 'vue';
    import LazyLoadDirective from '@/directives/LazyLoadDirective';
    
    Vue.directive('lazyload', LazyLoadDirective);
    

    小结

    使用IntersectionObserver实现延迟加载非常简单,拥有很好的性能和用户体验,目前系统兼容性覆盖的比较广。当然,如果列表元素节点特别多时,也需要进行长列表优化。

    结尾

    感谢你的阅读,日前智云健康大前端团队正在参加掘金人气团队评选活动。如果你觉得还不错的话,那就来 给我们投几票 吧!

    今日总共可以投21票,网页7票,App7票,分享7票。感谢支持,2021我们还会创作更多的技术好文~~~

    你的支持是是我们最大的动力~


    起源地下载网 » 使用IntersectionObserver优化图片加载

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元