• 利用IntersectionObserver完成懒加载、加载更多


     IntersectionObserver  (交叉观察器)

    IntersectionObserver提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。

    IntersectionObserver对象被创建以后,其被配置为监听根中一段给定比例的可见区域。一旦IntersectionObserver被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;可以在同一个观察者对象中配置监听多个目标元素。

    var obj = new IntersectionObserver(callback, options);
    
    // 开始监听  element为单个dom元素,多个元素都需要监听 需要多次调用  同一个观察者对象中配置监听多个目标元素。
    obj.observe(element);
    
    // 停止监听
    obj.unobserve(element);
    
    // 销毁监听
    obj.disconnect();
    
    // 返回所有观察目标的对象数组 每个对象包含目标元素与根每次的相交信息。
    obj.takeRecords();

     

    callback回调函数中,参数是每一个监听的对象
     var obj = new IntersectionObserver(changes => {
          //changes是一个数组,数组中每个元素都是监听的对象,每个对象包含很多信息,提取出需要的进行判断
          changes.forEach(item => {
            let {
              isIntersecting,
              target
            } = item;
            if (isIntersecting) {
              lazyImgView(target);
    //满足条件后 停止监听
              obj.unobserve(target);
            }
          })
        }, options);
    每个对象包含8个属性

     

    time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
    target:被观察的目标元素,是一个 DOM 节点对象
    rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
    boundingClientRect:目标元素的矩形区域的信息
    intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
    intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
    isIntersecting是用来判断元素是否符合options中的可见条件

    例如:

      var options = {
          threshold: [0.7]
        }
        var obj = new IntersectionObserver(changes => {
          changes.forEach(item => {
            console.log(item)
            let {
              isIntersecting,
              target
            } = item;
    //target 出现70%,isIntersecting为true
            if (isIntersecting) {
              lazyImgView(target);
              obj.unobserve(target);
            }
          })
        }, options);

    接着看一下options

    这个 options 配置对象,有三个属性 threshold,root,rootMargin

      threshold,他是一个数组

        配置为 threshold: [0, 0.25, 0.5, 0.75, 1] 

          这个表示目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数

      root,监听元素的祖先元素Element对象,其边界盒将被视作视口。

        目标在根的可见区域的的任何不可见部分都会被视为不可见。

      rootMargin.一个在计算交叉值时添加至根的边界盒中的一组偏移量

        可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和CSS 中的margin 属性等同,默认值是"0px 0px 0px 0px" (字符串) 该属性还没有正式使用

        在交叉检测开始之前,由rootMargin规定的矩形的每一边都会被添加至root元素的边框盒的相应边。例如,可以让你向外调整边界,使得目标元素被认为是100%可见的,即使此元素得一部分长或宽被裁剪,或者在边缘过于靠近根边框盒边界的情况下,将目标视为部分隐藏。

        相关介绍

    浏览器兼容:

    html:

     

     

    效果:

    (为了能够清晰的分辨 加载更多的出现,每次请求的数据和新数据之间有一个空,所以能够看到有一个空缺)

     

     

    完整代码:

    var imgListMoudule = (function () {
      // 获取操作得dom元素
      var container = $('#imgList'),
        page = 1,
        supportNumber = 0;
      // 获取数据 分页加载
      var queryData = (page) => {
       //假数据
        data = [{
          imgurl: "img/img.png",
          id: "1"
        }, {
          imgurl: "img/img.png",
          id: "2"
        }, {
          imgurl: "img/img.png",
          id: "3"
        }, {
          imgurl: "img/img.png",
          id: "4"
        }, {
          imgurl: "img/img.png",
          id: "5"
        }, {
          imgurl: "img/img.png",
          id: "6"
        }, {
          imgurl: "img/img.png",
          id: "7"
        }, {
          imgurl: "img/img.png",
          id: "8"
        }, {
          imgurl: "img/img.png",
          id: "9"
        }]
    
        bindHtml(data);
        // $.ajax({
        //   type: "POST",
        //   url: "",
        //   data: "",
        //   async: true,
        //   success: function (data) {
        //     data = [{
        //       imgurl: "",
        //       id: "1"
        //     }]
             if (page > 3) {
              // 数据没有了 将加载更多的元素去掉 不会再触发加载更多
              $('.load_more').hide();
            }
            bindHtml(data);
            ++page;  
        //   },
        //   error: function () {
        //     console.log("提交失败!");
        //   }
        // });
      }
      // 页面渲染
      var bindHtml = data => {
        var result = [];
        for (var i = 0; i < data.length; i += 2) {
          result.push(data.slice(i, i + 2));
        }
        var str = "";
        result.forEach(itemArray => {
          str += ` <div class="img_list_box" lazyload>`;
          itemArray.forEach(item => {
            str += `<a href="javascript:void(0)" class="img_item" data-id="${item.id}">
                                <div class="img_box" data-id="${item.id}">
                                    <img src="" alt="" class="index_img" data-realUrl="${item.imgurl}">
                                </div>
                                <div class="img_text">
                                    <div class="look_box img_text_item">
                                        <span>111</span>
                                        <img src="img/look_icon.png" alt="">
                                    </div>
                                    <div class="zan_box img_text_item">
                                        <span>111</span>
                                        <img src="img/zan_icon.png" alt="" class="zan_btn">
                                    </div>
                                </div>
                            </a>`;
          })
          str += ` </div>`;
        })
        container.append(str);
    
      }
      // 懒加载监听
      var lazyLoad = () => {
        var options = {
          threshold: [0.7]
        }
        var obj = new IntersectionObserver(changes => {
          changes.forEach(item => {
            let {
              isIntersecting,
              target
            } = item;
            if (isIntersecting) {
              lazyImgView(target);
              obj.unobserve(target);
            }
          })
        }, options);
        // 获取需要懒加载的元素  只获取设置了lazyload属性得元素
        var imgBox = $('.img_list_box[lazyload]');
        [].forEach.call(imgBox, lazyImg => {
    
          obj.observe(lazyImg);
        })
      }
      // 懒加载渲染
      var lazyImgView = item => {
        var imgs = $(item).find('.img_box img');
        // 防止之前数据重新渲染,移除掉已经监听得
        item.removeAttribute('lazyload');
        [].forEach.call(imgs, img => {
          img.src = img.getAttribute('data-realUrl');
    
          img.onload = () => {
            img.style.opacity = 1;
          }
        })
      }
      // 加载更多
      var loadMore = () => {
        var options = {
          threshold: [0.5]
        }
        var loadMoreDom = document.getElementsByClassName('load_more')[0];
        if (!loadMoreDom) {
          return false;
        }
        var obj = new IntersectionObserver(changes => {
    
          if (changes[0].isIntersecting) {
            queryData(page);
            lazyLoad();
          }
        }, options);
    
        obj.observe(loadMoreDom);
      }
    
     
      return {
        async init() {
          queryData(page);
          lazyLoad();
          loadMore();
    
        }
      }
    
    })();
    imgListMoudule.init();
    

      

      

      参考

      IntersectionObserver API 使用教程

      intersectionObserver WebApiI

       附带一个用scroll实现下拉加载的链接

  • 相关阅读:
    在SQL Server通过DBLINK执行ORACLE存储过程
    WIFI无线网卡全双工
    ORACLE判断日期、时间的字符串是否有效日期、时间
    FN_SPLIT-表值函数, 将字符串转列表
    EBS-从职责到报表名
    LeetCode 791 自定义字符串排序
    cgit——github快速下载器
    Ubuntu 16.04下使用git clone时报“gnutls_handshake() failed: Error in the pull function”错误
    LeetCode 1702 修改后的最大二进制字符串
    一个因编码习惯不正确而产生的BUG
  • 原文地址:https://www.cnblogs.com/GoTing/p/13903449.html
Copyright © 2020-2023  润新知