瀑布流探索

开发 · 02-29 · 81 人浏览

今天逛掘金的时候,突然逛到了瀑布流的推送,故进行学习

columns布局

该方式仅适合数据固定,且从下往上,再左往右展示的情况,那我们仅需要依赖CSS就可以完成
<div class="container">
        <div class="item">
            <img src="./imgs/1.jpg"/>
            我是一段文字用于占位
        </div>
        <div class="item">
            <img src="./imgs/2.jpg"/>
            我是一段文字用于占位,如果我特别长的话会怎么样,说实话我也不知道,这一切还要看效果
        </div>
        <div class="item">
            <img src="./imgs/3.jpg"/>
            我是一段文字用于占位
        </div>
.container{
        columns: 2;
        column-gap: 10px;
       }
       .container .item{
        margin-bottom:10px;
        border:1px solid #ccc;
        break-inside: avoid;
       }
       .item img{
        width:100%;
       }

2024-02-29T08:21:53.png

Grid实现

小知识,~~按位非运算符两次之后可以直接取整数部分
import List from './list.json'
  import { onMounted, ref } from 'vue'

  const imgsRef = ref(null)

  // 动态计算高度
  onMounted(() => {
    Array.from(imgsRef.value as any).forEach((img: HTMLImageElement) => {
      let src = img.getAttribute('url')! // 非空断言
      let image = new Image()
      image.src = src //得到图片的地址

      // 当前宽度, 被grid自动分配的宽度 假设总430,那么算间距现在一份可能是135
      let width = img.width

      image.onload = () => {
        let w = image.width // 图片宽度
        let h = image.height // 图片高度
        // 计算需要的高度比,用加载好图片后的高度 * 原来的宽度 除 现在的宽度
        // todo  其实直接用图片高度也行的, 不知道为什么这里要计算
        // 假设图片 300 * 240, 240 * 300 / 135
        let height = Math.round((h * width) / w)
        img.src = src
        // 设置跨越几个网格 即份数
        img.style.gridRowEnd = `span ${~~(height / 10)}`
      }
    })
  })
<div class="container">
    <img
      v-for="i in List"
      :url="i.img"
      :key="i.id"
      class="item"
      ref="imgsRef"
      width="100%"
      height="100%" />
  </div>
 .container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr; // 分为3列
    column-gap: 5px; // 列间距5px
    grid-auto-rows: 10px;
    .item {
      grid-row-start: auto;
    }
  }

这里的核心就是grid-auto-rows和grid-row-start,让网格开始跨越份数自动计算,通过动态计算图片高度,给予网格结束位置的跨越份数

Flex实现

不同于Grid, Flex需要手动控制列的布局(Flex是一维布局),还需要控制数据的手动拼接,核心还是CSS的布局

布局

<div class="container">
    <div class="col">
      <img v-for="i in List1" :src="i.img" :key="i.id" class="item" />
    </div>
    <div class="col">
      <img v-for="i in List2" :src="i.img" :key="i.id" class="item" />
    </div>
  </div>

JS逻辑

import List from './list.json'
  import { ref } from 'vue'

  const List1 = ref<any[]>([])
  const List2 = ref<any[]>([])
  const i = ref(0)

  while (i.value < List.length) {
    List1.value.push(List[i.value++])
    if (i.value < List.length) List2.value.push(List[i.value++])
  }

样式

.container {
    display: flex;
    flex-direction: row;
  }
  .col {
    display: flex;
    flex-direction: column;
    flex: 1;
    .item {
      width: 100%;
      margin-bottom: 10px;
    }
  }

2024-02-29T09:34:14.png

总结

三种方案来看,如果要结合实际业务使用还是推荐Flex布局,大多数情况下我们都要去计算最小高度列来进行数据插入.

说个题外话,要好好学习下Grid布局了,近期就把书肝完
CSS 瀑布流
Theme Jasmine by Kent Liao