IntersectionObserver 实现滚动加载

2,040 阅读2分钟

IntersectionObserver 实现滚动加载

  • 如果你不喜欢繁琐onscroll,那么试一试IntersectionObserver吧
  • 下面有完整代码,逻辑写在注释里了

话不多说上代码

  • html / css
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }

    .box {
      display: flex;
      flex: 1;
      flex-direction: column;
      width: 400px;
      height: 100%;
      margin: 0 auto;
      border: 1px solid blue;
      min-height: 100px;
      max-height: 600px;
      margin-top: 30px;
      overflow: auto;
    }

    .list {
      flex: 1;
    }

    .top {
      width: 100%;
      height: 50px;
    }

    .bottom {
      width: 100%;
      min-height: 50px;
      background: #ccc;
      text-align: center;
      line-height: 50px;
    }

    .item-list {
      width: 90%;
      height: 100px;
      border: 1px solid red;
      margin: 10px auto;
    }
  </style>
</head>

<body>
  <div id="content" class="box">
  	
    <ul id="list" class="list">
    	 // 数据加载位置 
    </ul>
    
    // 加载触发守卫
    <div id="bottom" class="bottom">...LoadingMore....</div>
  </div>
</body>
<script src="./index.js"></script>

</html>
  • js
let list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]


class LoadMore {
  constructor(options) {
    this.observer = null;
    this.rootNode = document.getElementById(options.root); // 父级容器
    this.obsNode = document.getElementById(options.obs); // 守卫节点
    this.loadMoreFn = options.loadMoreFn // 加载回调
    this.pageNum = 0; // 记录页数
    this.total = -1; // 总页数 -1 // 尚未获取
    this.init() // 初始化
  }
  // 交叉触发回调
  callback = (entries) => {
    console.log(111)
    // 防止插入瞬间再次触发离开交叉事件
    if (entries[0].intersectionRatio === 0) return;
    this.pageNum += 1
    this.loadMoreFn(this.pageNum)
  }
  // 关闭交叉监听
  canclobserve() {
    console.log('完毕')
    this.observer.unobserve(this.obsNode)

  }
  // 设置首位节点交叉监听
  hanldeObserve() {
    this.observer.observe(this.obsNode)
  }
  // 初始化
  init() {
  	 // 创建 IntersectionObserver 实例子
    this.observer = new IntersectionObserver(this.callback, {
      root: this.rootNode || null, // 交叉窗口、根元素
      rootMargin: '0px', // 交叉窗口边界扩展或者伸缩
      threshold: 0.8 // 交叉占比(0~1),达到该比例才触发回调
    });
    this.hanldeObserve()
  }
}

let loadEx = new LoadMore({
  root: 'content',
  obs: 'bottom',
  loadMoreFn: (pageNum) => {
    //  最好一页关闭监听
    if (pageNum * 10 > list.length) {
      loadEx.canclobserve()
    }
  	 // 插入dom
    let curPage = list.slice((pageNum - 1) * 10, pageNum * 10)
    // 创建文档碎片
    let frm = document.createDocumentFragment();
    for (let i = 0; i < curPage.length; i++) {
      let li = document.createElement('li')
      li.innerHTML = curPage[i];
      li.className = "item-list"
      frm.appendChild(li)
    }
    document.getElementById('list').appendChild(frm);
    frm = null;
  }
})