article-item-slide.vue 3.63 KB
<template>
  <div class="article-item-slide">
    <Slide :data="data.blockList" :threshold="0.2" :auto-play="false" :loop="false" :options="scrollOption" @change="onChange">
      <SlideItem :style="slideItemStyle" v-for="(item, inx) in data.blockList" :key="inx">
        <ArticleItemSlideImage :lazy="lazy" :data="item" :thumb-size="firstBlockSize"></ArticleItemSlideImage>
      </SlideItem>
      <template slot="dots" slot-scope="props">
        <span class="slide-dot"
          :class="dotClass(props.current, inx)"
          v-for="(item, inx) in props.dots"
          :key="inx">
        </span>
      </template>
    </Slide>
    <div class="pages">
      {{currentIndex}}<span class="small">/{{data.blockList.length}}</span>
    </div>
  </div>
</template>

<script>
import {first} from 'lodash';
import {Slide} from 'cube-ui';
import {mapState} from 'vuex';
import ArticleItemSlideImage from './article-item-slide-image';

export default {
  name: 'ArticleItemSlide',
  props: {
    data: {
      type: Object,
      default() {
        return {};
      }
    },
    lazy: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      scrollOption: {
        eventPassthrough: 'vertical'
      },
      currentIndex: 1,
    };
  },
  computed: {
    ...mapState(['yoho']),
    slideItemStyle() {
      const {width, height} = this.firstBlockSize;

      if (width && height) {
        return {
          width: `${width}px`,
          height: `${height}px`,
          display: 'flex',
          'justify-content': 'center',
          'align-items': 'center'
        };
      }
    },
    firstBlockSize() {
      const {width, height} = first(this.data.blockList) || {};

      if (width && height) {
        const scale = width / height;

        return {
          width: this.yoho.window.clientWidth,
          height: this.yoho.window.clientWidth / scale,
        };
      }
      return {};
    }
  },
  methods: {
    onChange(inx) {
      this.currentIndex = inx + 1;
    },
    dotClass(current, inx) {
      const offset = 1;
      const len = this.data.blockList.length;
      let left = current - offset;
      let right = current + offset;

      if (left < 0) {
        const offsetRight = 0 - left;

        if (right + offsetRight > len - 1) {
          right = len - 1;
        } else {
          right += offsetRight;
        }
        left = 0;
      } else if (right > len - 1) {
        const offsetLeft = right - (len - 1);

        if (left - offsetLeft < 0) {
          left = 0;
        } else {
          left -= offsetLeft;
        }
        right = len - 1;
      }

      return {
        active: current === inx,
        more: !(inx >= left && inx <= right),
        hide: left - inx > 1 || inx - right > 1
      };
    }
  },
  components: {Slide, SlideItem: Slide.Item, ArticleItemSlideImage}
};
</script>

<style lang="scss" scoped>
.article-item-slide {
  position: relative;
  width: 750px;
  overflow: hidden;

  & /deep/ .cube-slide-dots {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 10PX;
    height: 5PX;
  }
}

.slide-dot {
  width: 30px;
  height: 8px;
  background-color: rgba(255, 255, 255, 0.7);
  transition: width 0.2s linear;

  &.active {
    background-color: rgba(255, 255, 255, 1);
  }

  &.more {
    width: 8px;
  }

  &.hide {
    display: none;
  }
}

.pages {
  position: absolute;
  top: 0;
  right: 0;
  width: 88px;
  height: 54px;
  background: rgba($color: #000, $alpha: 0.5);
  border-radius: 0 0 0 30px;
  color: #fff;
  font-size: 28px;
  display: flex;
  line-height: 24px;
  justify-content: center;
  align-items: center;

  .small {
    transform: scale(0.7);
    padding-top: 3PX;
  }
}
</style>