瀑布流布局+无限滚动

瀑布流:列对齐方式布局

无限滚动:到底触发事件,获取内容更新至页面

实现:

通过web api里的IntersectionObserver,某标签出现在浏览器视口,就触发回调,瀑布流通过手动设置图片位置。

IntersectionObserver参考文档:

https://wangdoc.com/webapi/intersectionObserver.html#%E6%83%B0%E6%80%A7%E5%8A%A0%E8%BD%BD%EF%BC%88lazy-load%EF%BC%89

实现代码:

<!DOCTYPE html>
<html lang="en">

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

    .container {
      position: relative;
    }

    .container>div {
      position: absolute;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .container>div img {
      width: calc(100% - 0.5em);
      margin: 0.2em;
    }
  </style>
</head>

<body>

  <div style="height: 2em;display: flex;justify-content: center;align-items: center;">
    头部
  </div>

  <div class="container">

  </div>

  <div id="bottom" style="height: 2em;display: flex;justify-content: center;align-items: center;">
    底部
  </div>

  <script>

    // 获取随机整数
    function getRandomInt(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    // 随机图片列表(测试用)
    let imgs = [
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fgss0.baidu.com%2F7Po3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2F30adcbef76094b364b18a31ca2cc7cd98c109dbd.jpg&refer=http%3A%2F%2Fgss0.baidu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626869559&t=27bf6e2ea4f853fdcb30f8a3f3068981",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13584429185%2F1000&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626869720&t=606d140718cd1def9e8ec81c3a1b8d5f",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftu1.whhost.net%2Fuploads%2F20181207%2F10%2F1544150166-YIVJLsFmDK.jpg&refer=http%3A%2F%2Ftu1.whhost.net&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626869720&t=6a417c65f0732b4e2a8ed3d0071f1608",
      "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=291238033,2983030545&fm=26&gp=0.jpg",
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fgss0.baidu.com%2F7Po3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2F3ac79f3df8dcd100adaf61ec728b4710b8122fcf.jpg&refer=http%3A%2F%2Fgss0.baidu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626870982&t=070f2f6f50e363fb3499711334b85d16",
      "https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/3801213fb80e7bec8c1d93942d2eb9389a506b84.jpg",
    ]

    // 瀑布流高度列表,每次都在最低列上
    let heights = []
    // 瀑布流列数
    let coloum = 5

    // 观察器,监测底部元素,快到那里就添加元素
    let observer = new IntersectionObserver((entries, observer) => {
      // 底部只会有一个,所以这样写了
      let entrie = entries[0]
      let ratio = entrie.intersectionRatio
      console.log(`漏出${parseInt(ratio * 100)}%`, entries);
      // 获取图片
      if (ratio >= 0.2 && ratio <= 1) {
        // 获取图片数据

        // 添加元素,每次随机搞了15个(图片少可能触发不了,由图片高度决定,3行一般是肯定能)
        for (let i = 0; i < 15; i++) {
          let container_div = document.getElementsByClassName("container")[0]
          let div_img = document.createElement("div")
          let img = document.createElement("img")
          // 由于需要更方便的设置内边距所以图片外套了一个div
          div_img.style.width = `calc(${100 / coloum - 0.2}%)`
          div_img.append(img)
          // 设置图片路径,添加dom
          img.src = imgs[getRandomInt(0, imgs.length - 1)]
          container_div.appendChild(div_img)
          // 图片加载成功就需要设置位置,不在加载成功搞div撑不起来
          img.onload = () => {
            // 判断是否是第一行
            if (heights.length < coloum) {
              div_img.style.top = 0
              div_img.style.left = `${div_img.offsetWidth * heights.length}px`
              heights.push(div_img.offsetHeight)
            } else {
              // 找最低一列索引,每次都在最低列下面
              let index = heights.indexOf(Math.min(...heights))
              div_img.style.top = `${heights[index]}px`
              div_img.style.left = `${div_img.offsetWidth * index}px`
              heights[index] += div_img.offsetHeight
            }
            // 手动设置容器高度
            let max_height = Math.max(...heights)
            container_div.style.height = `${max_height}px`
          }
        }
        // 获取不到图片,关闭观察器
        if (document.getElementsByTagName("img").length >= 45) {
          observer.disconnect()
        }
      }
    }, { threshold: [0.2] })

    // 底部标签漏出5分之1就加载图片
    observer.observe(document.getElementById("bottom"))

  </script>

</body>

</html>

效果图:

原文地址:https://www.cnblogs.com/zezhou/p/14922797.html