<template>
  <div id="waterfall" class="narrow-scrollbar" ref="waterfall">
    <div
      class="img-box default-card-animation"
      v-for="(item, index) in imgsArr_c"
      :key="index"
      :style="{ width: imgWidth + 'px', height: item._height + 'px' }"
      ref="imgBox"
    >
      <img :data-src="item.src" />
    </div>
    <ScrollLoad
      :el="scrollEl"
      :maxLen="maxLen"
      :curLen="curLen"
      :hasMorePages="hasMorePages"
      :loadingMore="loadingMore"
      @submit="onNextPage"
    ></ScrollLoad>
  </div>
</template>

<script>
import { isMobile, getDocumentSize, throttle } from '@/utils/tool';
import ScrollLoad from '@/components/custom/ScrollLoad.vue';
import { PageScrollId, PageContentWidth } from '@/constants/token';
export default {
  name: 'waterfall',
  props: {
    list: Array,
    maxLen: Number,
    curLen: Number,
    hasMorePages: Boolean,
    loadingMore: Boolean,
  },
  emits: ['submit'],
  components: {
    ScrollLoad,
  },
  data() {
    return {
      imgsArr: [],
      imgsArr_c: [], // 渲染的图片
      imgCol: 5, // 图片列数
      imgGap: 5, // 图片间间隔
      loadedCount: 0,
      imgBoxEls: [], // 所有 img-box 元素
      beginIndex: 0,
      colsHeightArr: [], // 保存当前每一列的高度
      reachBottomDistance: 20, // 滚动触底距离，触发加载新图片
      viewHeight: 0, // 窗口视图大小
      scrollEl: null,
      viewWidth: 0, // 窗口宽度
      //   规定五个最大值
      widthList: [
        {
          max: 1597,
          value: 5,
        },
        {
          max: 1304,
          value: 4,
        },
        {
          max: 1011,
          value: 3,
        },
        {
          max: 718,
          value: 2,
        },
        {
          max: 425,
          value: 1,
        },
      ],
      //   图片宽度
      imgWidth: 0,
    };
  },
  computed: {
    isMobile() {
      return isMobile();
    },

    // 列数
    colNum() {
      return this.isMobile ? 2 : this.imgCol;
    },
  },
  watch: {
    imgsArr(newVal, oldVal) {
      if (
        this.imgsArr_c.length > newVal.length ||
        (this.imgsArr_c.left > 0 && newVal[0] && !newVal[0]._height)
      )
        this.reset();
      this.preLoad();
    },
    // 数组改变
    list(newVal, oldVal) {
      this.imgsArr = newVal;
    },
  },
  methods: {
    // 获取dom元素
    getDom() {
      return document.getElementById('waterfall');
    },
    // 列宽度
    colWidth() {
      const el = this.getDom();
      if (el) {
        return el.clientWidth / this.colNum;
      }
    },
    // 获取图片宽度
    getImageWidth(el) {
      return el.clientWidth / this.imgCol - 2 * this.imgGap;
    },
    onNextPage() {
      this.$emit('submit');
    },
    // 预加载 设置图片宽高
    preLoad() {
      // forEach 无法通过 item 直接修改数组元素，需用数组下标修改
      this.imgsArr.forEach((item, index) => {
        if (index < this.loadedCount) return;
        if (!item.src) {
          this.imgsArr[index]._height = '0';
          ++this.loadedCount;
          if (this.imgsArr.length === this.loadedCount) {
            this.preloaded();
          }
        } else {
          let img = new Image();
          img.src = item.src;
          img.onload = img.onerror = (e) => {
            // 若加载失败则设置图片高度与宽度一致，加载成功则动态计算图片高度
            this.imgsArr[index]._height =
              e.type === 'load'
                ? Math.round(this.imgWidth * (img.height / img.width))
                : this.imgWidth;
            if (e.type === 'error') {
              this.imgsArr[index]._error = true;
            }
            ++this.loadedCount;
            if (this.imgsArr.length === this.loadedCount) {
              this.preloaded();
            }
          };
        }
      });
    },
    preloaded() {
      this.imgsArr_c = [].concat(this.imgsArr);
      this.$nextTick(() => {
        this.waterfall();
      });
    },
    // waterfall 布局
    waterfall() {
      // 等到整个视图都渲染完毕再执行
      this.imgBoxEls = this.$refs['imgBox'];
      if (!this.imgBoxEls) return;
      let top, left, height;
      //
      this.beginIndex = 0;
      if (this.beginIndex === 0) this.colsHeightArr = [];
      for (let i = 0; i < this.imgBoxEls.length; ++i) {
        if (!this.imgBoxEls[i]) return;
        height = this.imgBoxEls[i].offsetHeight;
        console.log(height);
        // 第一行
        if (i < this.colNum) {
          this.colsHeightArr.push(height);
          top = 0;
          left = i * this.colWidth();
        } else {
          // 找到最低的高度和其索引
          let minHeight = Math.min.apply(null, this.colsHeightArr);
          let minIdx = this.colsHeightArr.indexOf(minHeight);
          top = minHeight;
          left = minIdx * this.colWidth();
          this.colsHeightArr[minIdx] += height;
        }
        // 设置 img-box 位置
        this.imgBoxEls[i].style.top = top + 'px';
        this.imgBoxEls[i].style.left = left + 'px';
        // 加载图片
        let imgEl = this.imgBoxEls[i].children[0];
        imgEl.src = imgEl.getAttribute('data-src');
        imgEl.style.opacity = 1;
        imgEl.style.transform = 'scale(1)';
      }
      this.beginIndex = this.imgBoxEls.length;
    },
    reset() {
      this.imgsArr_c = [];
      this.beginIndex = 0;
      this.loadedCount = 0;
    },

    // 屏幕宽度监听
    ColumnsChange(e) {
      const el = this.getDom();
      // 重新计算图片宽度
      this.imgWidth = this.getImageWidth(el);
      this.waterfall();
    },
  },
  mounted() {
    const el = this.getDom();
    if (el) {
      this.imgWidth = this.getImageWidth(el);
      this.viewHeight = el.clientHeight;
      this.preLoad();
    }
    // 获取滚动元素
    this.scrollEl = document.getElementById(PageScrollId);
    // 可视区域宽高
    const client = getDocumentSize();
    this.viewWidth = client.width;

    // 开启屏幕宽度监听
    window.addEventListener('resize', throttle(this.ColumnsChange, 500));
  },
};
</script>

<style scoped lang="less">
#waterfall {
  width: 100%;
  position: relative;
  @keyframes show-card {
    0% {
      transform: scale(0.5);
    }

    100% {
      transform: scale(1);
    }
  }

  .img-box {
    position: absolute;
    border-radius: 10px;
    padding: 5px;
    padding-left: 0;
    transition: all 0.2s;

    img {
      width: 100%;
      border-radius: 10px;
      opacity: 0;
      transform: scale(0.5);
      transition: all 0.6s;
      transition-delay: 0.1s;
    }
  }

  /* .default-card-animation {
      animation: show-card 0.4s;
      transition: left 0.6s top 0.6s;
      transition-delay: 0.1s;
    } */
}
</style>
