简单瀑布流实现

416 阅读3分钟

Emmmmm,其实之前我有一篇文章已经说瀑布流的了,不过那篇是grid布局的,无限加载会到之重绘,不太理想的解决方案。

瀑布流,我觉得很复杂,所以一直没敢碰,对瀑布流一直有一种恐惧,看别的作者的文章我也懒得看,哈哈,因为感觉写的有点难看懂哈,或者就是都是说双列,万一我要4列捏,灵活性不够,而且我性子急,耐不下心来。

然后,今天早上捏就下定决心,满脑子都是怎么实现,写了一下,发现也写出来了,嘿嘿,满开森的,也是用grid实现,不过这次只是用grid布局。

首先捏,咱们根据需求定义需要的列数,然后把每一列的图片循环展示出来就好啦。那每一列要有一个数组来记录每一列的高度,只是记录,方便寻找到最矮的那一列,下次加载图片就找到最矮的那一列,push进去就好啦。

我用的vue实现,其实用其他技术都一样的,小程序啥啥的都行。

先看html块

<div id="waterfall-page">
    <!--[ vue template根标签 ]-->
    <div class="waterfall">
      <!--[ 这是瀑布流的容器 ]-->
      <div class="waterfall-column" v-for="(column,columnIndex) in columns" :key="columnIndex">
        <!--[ waterfall-column 就是每一列 比如我要5列 就会循环出 5 列来 然后循环每一列里面的图片 ]-->
        <div
          class="waterfall-column-images"
          v-for="(columnImages,columnImageIndex) in column"
          :key="columnImageIndex"
        >
          <!--[ waterfall-column-images 就是列里面的图片  ]-->
          <div class="waterfall-column-image-item">
            <!--[ 图片的每一项,为啥拿个div包裹捏,因为可能用上标题,当然不用div包裹也可以的哈  ]-->
            <img class="waterfall-column-image" :src="columnImages['src']" />
            <!--[ waterfall-column-image 就是每一张图片啦  ]-->
            {{ Math.random() }}
            <!--[ 这是随机数字串的标题  ]-->
          </div>
        </div>
      </div>
    </div>
  </div>

然后css叭

.waterfall {
  display: grid;
  grid-template-columns: repeat(5, 19%); /* 目前是5列,每列占据页面的19% */
  column-gap: 1%; /* 每列是1%的间距 */
  width: 100%;
}
.waterfall-column-image-item {
  margin-bottom: 20px; /* 图片的距离下一个元素的高度,反正大概意思吧。 */
}
.waterfall-column-image {
  width: 100%; /* 每一个图片默认100%的宽度,也就是grid的每一列宽度,这样就会跟着 grid 的每一列 的宽度改变了 */
}
.waterfall-column-image:hover {
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); /* 鼠标经过图片后加投影而已 */
}

到JS了,主要就是循环图片数组,根据图片的宽高放到最矮的那一列去

代码有些许冗余,没优化

export default {
  mounted() {
    let columns = []; // 每一列的图片
    let columnsHeight = []; // 每一列的高度
    for (let i = 0; i < this.columnCount; i++) {
      //根据设定的列数循环,往columns和coumnsHeight push进去
      /* 假如我要5列,那我就循环5次,那肯定要有5个变量存储这5列的高度的,所以就往coumnsHeight里面push5个0进去,开头都是0高度,都别争 */
      /* 我还是要5列,那也还是要有5个变量记录存储每一列的图片的,所以就用一个二维数组存储,这个二维数组的第一维就是每一列啦。那每一列也是一个数组,这就是第二维了,里面存储了图片 */
      columns.push([]);
      columnsHeight.push(0);
    }
    for (let i = 0; i < this.images.length; i++) {
      //就循环图片数据,根据图片的高度放到不同的列
      let min = Math.min.apply(null, columnsHeight); // 寻找出最矮的那一列
      let minIndex = columnsHeight.indexOf(min); //根绝找到最矮的那一列元素找出它的索引,比如  [99,56,42,22,33] 找到最小的数字,也就是22 但是Math.min只返回这个22 不返回索引,所以就要根据22找到它的索引
      columns[minIndex].push(this.images[i]); //然后就把图片push进去最矮的那一列
      columnsHeight[minIndex] += this.images[i]["height"]; //那这一列就要加上这个图片的高度,不然它就永远最矮了。
    }
    this.columns = columns; //赋值
    this.columnsHeight = columnsHeight; //赋值
    window.onscroll = () => {
      //当页面滚动到底部的时候加载数据
      if (window.scrollY >= document.body.offsetHeight - window.innerHeight) {
        this.images.push(
          ...[
            {
              src:
                "https://hbimg.huabanimg.com/a1d9aee50e576abd7a24006e3aebc744cbd1562c696e5-MqpR3I_fw236/format/webp",
              height: 352,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/d3c8cb9a00ae00cbb3600789932c4a8a2d8bb3cf45f375-1iUVTy_fw236/format/webp",
              height: 3327,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/7c3f9e6c0205218c3ec59e1f3df117d10abf783f4b6586-erfNZi_fw236/format/webp",
              height: 309,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/064b4effab7541d708222784d0ca4bd454b95da951194-qlzUkS_fw236/format/webp",
              height: 420,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/17c62838f0e57d4aa294ad40951afd722ab6cce19b501-LWVAFa_fw236/format/webp",
              height: 208,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/02ccd93685bfe58bf0514160ae57a7ae7b40fad32d0ea-1Fe105_fw236/format/webp",
              height: 320,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/49d7af245eaf403a54f36741498a5faf7bac9b2e52e87-qzHef5_fw236/format/webp",
              height: 353,
              width: 236,
            },
            {
              src:
                "https://hbimg.huabanimg.com/0ac47eea86d58750b7239526eaeb0475470de96f17ba4-2rflnj_fw236/format/webp",
              height: 195,
              width: 236,
            },
          ]
        );
        for (let i = this.images.length - 5; i < this.images.length; i++) {
          //这一块代码是复制过来的,跟上面的意思一毛一样的,只是这里循环的开头是图片数据数组的长度-5 因为我要计算的是最后Push进去的那5个元素,这5个前面的就不用计算了,已经计算过了。
          let min = Math.min.apply(null, columnsHeight);
          let minIndex = columnsHeight.indexOf(min);
          this.columns[minIndex].push(this.images[i]);
          this.columnsHeight[minIndex] += this.images[i]["height"];
        }
      }
    };
  },
  data() {
    return {
      images: [
        //就图片的数据,宽高都有
        {
          src:
            "https://hbimg.huabanimg.com/e825b601f4c487dab1ebed5457960177306092b178fa0-QkaBzg_fw236/format/webp",
          height: 133,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/1eac8368f6063ecf0197b6ddb0cbcd11125893a92f061-RQSaDl_fw236/format/webp",
          height: 130,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/7e86b07e4c838e19b8a0371ba715bc2b4b2192c2fa67-EXyYWc_fw236/format/webp",
          height: 334,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/05a99dd361d5dcbc2353e5ddf28a2ae833a7ca75bb406-glSLik_fw236/format/webp",
          height: 86,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/8db6ddd77cd893f548a03a181626872f7286aa88d64e54-9YiWmo_fw236/format/webp",
          height: 1175,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/7122a1a51de0606142ae40b94acf30fedae9523b6bcae-3hMBSL_fw236/format/webp",
          height: 420,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/4f6e0cd4643b9e9ac9b9d894c9165d228eebd320688b4-ZWmBZ6_fw236/format/webp",
          height: 1055,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/4318d4c389dd51a4b318426fa32724a9153c421c15cc3b-e2FcLS_fw236/format/webp",
          height: 278,
          width: 236,
        },
        {
          src:
            "https://hbimg.huabanimg.com/d8f0c9f9c395b8d3976326241cc24002b38851f31f1166-efL5nW_fw236/format/webp",
          height: 334,
          width: 236,
        },
      ],
      columns: [], //每一列的图片 
      columnsHeight: [], //记录每一列的高度 
      columnCount: 5, //列数
    };
  },
};

5列效果

然后改成4列

或者3列的

如果用在移动端、小程序应该是没问题的,主要核心就是根绝每个图片的高度放到最矮的那一列而已,grid兼容问题,不考虑IE和太旧的浏览器的话,没啥问题的。 掘金的肥文本编辑器是不是有些许问题,复制了代码,就会错乱,切换到MK没啥问题

我发现,有时候不是做不出来,只是 懒 或者 怕~

很少写文章,有些地方写的不太清楚的,可以评论一下。 只能尽量写明白,写清楚。写文章真的不太好写,日常吹水我还是可以的。🤭