scroll-reveal.vue 4.23 KB
<template>
  <div class="sr-list">
    <div class="sr-col" v-for="(col, index) in colsList" :key="index" :style="`width:${100/cols}%`">
      <template v-if="col.length">
        <ArticleItem v-for="(item, index) in col" :key="item.articleId" class="sr-item" :data="item" :index="index" @click="onClick"  :tab="tab"></ArticleItem>
      </template>
      <ArticleItem class="sr-temp" :temporary="true" :index="0" :tab="tab"></ArticleItem>
    </div>
  </div>
</template>

<script>

import ArticleItem from './author-article-item';
import {assign, get, forEach} from 'lodash';
import {getArticleImageSize} from 'utils/image-handler';
import YAS from 'utils/yas-constants';

export default {
  data() {
    return {
      colsList: [],
      loadedIndex: 0,
      colsHeight: []
    };
  },
  props: {
    list: {
      type: Array,
      default: []
    },
    cols: {
      type: Number,
      default: 2
    },
    params: Object,
    tab: Number
  },
  created() {
    this.reset();
  },
  mounted() {
    this.$cols = this.$el.getElementsByClassName('sr-col');
    this.getCoverImgWidth();
  },
  watch: {
    list(newList, oldList) {
      if (oldList.length > newList.length ||
        get(oldList, '[0]._type') !== get(newList, '[0]._type')) {
        this.reset();
      }

      this.$nextTick(() => {
        this.calcListLayout();
      });
    }
  },
  methods: {
    getCoverImgWidth() {
      let imgWidth = this.$el.offsetWidth / this.cols;

      let $item = this.$el.getElementsByClassName('sr-temp');

      if ($item && $item.length) {
        let _w = $item[0].offsetWidth;

        let $img = $item[0].children;

        (_w > 0) && (imgWidth = _w);

        if ($img && $img.length) {
          _w = $img[0].offsetWidth;
          (_w > 0) && (imgWidth = _w);
        }
      }

      this.imgBlockWidth = imgWidth;
    },
    calcListLayout(single) {
      this.loadedIndex = this.loadedIndex || 0;

      let num = this.list.length - this.loadedIndex;

      if (num <= 0) {
        return;
      }

      forEach(this.$cols, (col, index) => {
        this.colsHeight[index] = col.offsetHeight;
      });

      let minHeight = Math.min.apply(null, this.colsHeight);

      let minIndex = this.colsHeight.indexOf(minHeight);

      let end = 1;

      if (!single) {
        end = Math.max.apply(null, [1, num - Math.floor(this.cols * 2)]);
      }

      for (let i = 0; i < end; i++) {
        let item = this.list[this.loadedIndex + i];

        if (item) {
          let index = (minIndex + i) % this.cols;

          this.colsList[index] = this.colsList[index] || [];
          this.colsList[index].push(this.clacCoverSize(item));
        }
      }

      this.colsList = [...this.colsList];
      this.loadedIndex += end;

      this.$nextTick(() => {
        this.calcListLayout(true);
      });
    },

    clacCoverSize(item) {
      let {width, height} = getArticleImageSize({
        width: item.imageWidth,
        height: item.imageHeight
      });

      return assign(item, {
        imageWidth: width,
        imageHeight: height,
        scale: height / width,
        blockWidth: this.imgBlockWidth
      });
    },

    reset() {
      this.loadedIndex = 0;

      let list = [];

      for (let i = 0; i < this.cols; i++) {
        list[i] = [];
      }

      this.colsList = list;
    },
    onClick({data, type}) {
      if (type === 'author') {
        this.toAuthor(data);
      } else {
        this.toArticle(data);
      }
    },
    toAuthor({authorUid, authorType}) {
      if (get(this.params, 'params.authorUid') === authorUid) {
        return;
      }

      this.$router.push({
        name: 'author',
        params: {
          id: authorUid,
          type: authorType
        }
      });
    },
    toArticle({articleId, sort}) {
      this.$router.push({
        name: 'article',
        params: {
          id: articleId
        },
        query: {
          report_yas: YAS.eventName.detailShow,
          report_param: {
            ART_ID: articleId,
            ATR_TYPE: sort === 2 ? 1 : 2
          }
        }
      });
    }
  },
  components: {
    ArticleItem
  }
};
</script>

<style lang="css">
  .sr-list {
    padding: 5px;
    display: flex;
    align-items: flex-start;

    .sr-col {
      flex-grow: 1;
      position: relative;
    }
  }
</style>