手写瀑布流

119 阅读1分钟
<template>
  <div class="waterfall" :style="{height: waterHeight + 'px'}">
    <div class="v-waterfall-content" id="v-waterfall">
      <div
        v-for="(img, index) in waterfallList"
        :key="index"
        class="v-waterfall-item"
        :style="{
          top: img.top + 'px',
          left: img.left + 'px',
          width: waterfallImgWidth + 'px',
          height: img.height,
        }"
      >
        <img :src="img.src" alt="" />
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
/* eslint-disable */
export default {
  name: "v-waterfall",
  data () {
    return {
      waterfallList: [],
      imgArr: [

      ],
      // waterfallImgWidth: 100,
      waterfallImgWidth: 0,// 每个盒子的宽度
      waterfallImgCol: 2,// 瀑布流的列数
      // waterfallImgCol: 3,// 瀑布流的列数
      waterfallImgRight: 10,// 每个盒子的右padding
      waterfallImgBottom: 10,// 每个盒子的下padding
      waterfallDeviationHeight: [],
      imgList: [],
      waterHeight: 0
    }
  },
  props: ['imgLists'],
  created () {
    this.imgArr = this.imgLists;
    // 触发入口
    for (let i = 0; i < this.imgArr.length; i++) {
      // this.imgList.push(this.imgArr[Math.round(Math.random() * 8)]);// 图片随机显示
      this.imgList.push(this.imgArr[i]);
    }
  },
  mounted () {
    console.log(this.waterfallList, 'waterfallList');
    this.calculationWidth();
  },
  methods: {
    //计算每个图片的宽度或者是列数
    calculationWidth () {
      let domWidth = document.getElementById("v-waterfall").offsetWidth;
      if (!this.waterfallImgWidth && this.waterfallImgCol) {
        this.waterfallImgWidth = (domWidth - this.waterfallImgRight * (this.waterfallImgCol - 1)) / this.waterfallImgCol;
        console.log(this.waterfallImgWidth, 'this.waterfallImgWidth')
      } else if (this.waterfallImgWidth && !this.waterfallImgCol) {
        this.waterfallImgCol = Math.floor(domWidth / (this.waterfallImgWidth + this.waterfallImgRight))
      }
      //初始化偏移高度数组
      this.waterfallDeviationHeight = new Array(this.waterfallImgCol);
      for (let i = 0; i < this.waterfallDeviationHeight.length; i++) {
        this.waterfallDeviationHeight[i] = 0;
      }
      this.imgPreloading()
    },
    //图片预加载
    imgPreloading () {
      for (let i = 0; i < this.imgList.length; i++) {
        let aImg = new Image();
        aImg.src = this.imgList[i];
        aImg.onload = aImg.onerror = (e) => {
          let imgData = {};
          imgData.height = this.waterfallImgWidth / aImg.width * aImg.height;
          imgData.src = this.imgList[i];
          // imgData.title = '标题';// 说明文字(也可以自己写数组,或者封装json数据,都可以,但是前提是你会相关操作,这里不赘述)
          // imgData.info = '详情说明:啦啦啦啦啦';// 说明文字
          this.waterfallList.push(imgData);
          this.rankImg(imgData);
        }
      }

    },
    //瀑布流布局
    rankImg (imgData) {
      let {
        waterfallImgWidth,
        waterfallImgRight,
        waterfallImgBottom,
        waterfallDeviationHeight
      } = this;
      let minIndex = this.filterMin();
      imgData.top = waterfallDeviationHeight[minIndex];
      imgData.left = minIndex * (waterfallImgRight + waterfallImgWidth);
      // waterfallDeviationHeight[minIndex] += imgData.height + waterfallImgBottom;// 不加文字的盒子高度
      waterfallDeviationHeight[minIndex] += imgData.height + waterfallImgBottom;// 加了文字的盒子高度,留出文字的地方(这里设置56px)

      this.waterHeight = this.getHeight();

    },
    /**
     * 找到最短的列并返回下标
     * @returns {number} 下标
     */
    filterMin () {
      const min = Math.min.apply(null, this.waterfallDeviationHeight);
      return this.waterfallDeviationHeight.indexOf(min);
    },

    filterMax() {
      const max = Math.max.apply(null, this.waterfallDeviationHeight);
      return this.waterfallDeviationHeight.indexOf(max);
    },

    getHeight() {
      return Math.max.apply(null, this.waterfallDeviationHeight);
    }
  }
}
</script>

<style scoped>
.waterfall {
  width: 100%;
  padding: 0 24px;
  margin: 0 auto;
}
.v-waterfall-content {
  /* 主要 */
  width: 100%;
  /*height: 80px;*/
  position: relative;
  /* 次要:设置滚动条,要求固定高度 */
}

.v-waterfall-item {
  /* 主要 */
  float: left;
  position: absolute;
}

.v-waterfall-item img {
  /* 主要 */
  /* width: auto;height: auto; */
  width: 100%;
  height: auto;
  /* 次要 */
  border-radius: 6px;
  padding-bottom: 100px;
}
</style>