封装vue瀑布流布局组件

最近在开发移动端页面时,发现好多都使用了瀑布流布局,又没找到个满意的组件,避免每次重复开发,就自行封装了个瀑布流布局组件

主要想说一下js的,也当是个人笔记,其他借助flex、column、Grid等纯css实现的瀑布流可以自行了解,那些要使用比较简单快捷的,当然每个都有它相应的缺点。

实现原理

根据数据与列参数,以数组嵌套数组为数据格式,通过v-for动态遍历渲染。

父盒子使用flex布局,在让列的盒子根据内容撑开高度。添加数据时,动态获取每列盒子的高度,往最小高度的列盒子数组添加数据,就可以实现瀑布流布局。

具体内容可以通过插槽添加

说的不太清楚,上代码:

<template>
  <div class="flow-wrapper">
    <div
      class="flow-col"
      v-for="(item, index) in showData"
      :key="index"
      :ref="'flowCol' + index"
    >
      <div class="flow-row" v-for="(v, i) in item" :key="i">
        <!-- 默认插槽 内容自定义 -->
        <slot :item="v"> </slot>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    // 列数
    itemColumn: {
      type: Number,
      default: 2,
    },

    // 数据来源
    flowData: {
      type: Array,
      default: () => [],
    },
  },
  watch: {
    flowData: {
      deep: true,
      handler(newV) {
        // 提取为渲染数据,避免重复操作整个数据
        this.loadData(newV.slice(this.loadTotal));
      },
    },
  },
  data: () => ({
    showData: [], // 用于渲染的数组
    loadTotal: 0, // 已经渲染数据总数
  }),
  methods: {
    // 处理数据,生成渲染数组
    loadData(arr) {
      for (let i = 0; i < arr.length; i++) {
        // 预加载图片
        let newImage = new Image();
        newImage.src = arr[i].src;
        newImage.onload = () => {
          if (this.showData.length < this.itemColumn) {
            // 生成列数组
            let colArr = [];
            colArr.push(arr[i]);
            this.showData.push(colArr);
          } else {
            let minIndex = this.findMinHeightColIndex(this.itemColumn);

            // 将数据插入最小高度的列
            this.showData[minIndex].push(arr[i]);
          }
        };
      }

      this.loadTotal = this.flowData.length;
    },

    findMinHeightColIndex(num) {
      let minIndex = 0;

      //根据动态绑定获取各列高度
      let minHeight = this.$refs["flowCol0"][0].offsetHeight;
      for (let k = 0; k < num; k++) {
        if (minHeight > this.$refs["flowCol" + k][0].offsetHeight) {
          minHeight = this.$refs["flowCol" + k][0].offsetHeight;
          minIndex = k;
        }
      }

      return minIndex;
    },
  },
};
</script>

<style lang="scss" scoped>
.flow-wrapper {
  width: 100%;
  display: flex;
  align-items: flex-start;

  .flow-col {
    flex: 1;
    margin-right: 10px;

    &:last-child {
      margin: 0;
    }

    .flow-row {
      border: 1px solid rgba(7, 17, 27, 0.1);
      border-radius: 6px;
      overflow: hidden;
      margin-bottom: 10px;
      background-color: #fff;

      &:last-child {
        margin: 0;
      }
    }
  }
}
</style>

效果图:
(仿美团的,数据是假数据,凑合看吧)
封装vue瀑布流布局组件_第1张图片

你可能感兴趣的:(瀑布流布局,vue,javascript)