利用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实现下拉加载的链接

posted @ 2020-10-30 20:33  明媚下雨天  阅读(670)  评论(0编辑  收藏  举报