手写卡片化层叠轮播图

3,399 阅读4分钟

效果图

竖屏移动端(vue + TS)

1.DOM

  <div class="home-swiper">
    <transition name="fade">
      <div @touchend='end' @touchstart='start' @touchmove='move' class="swiper">
        <div @click="chooseItem(item,index, config5[index])" v-for="(item, index) in imgs" :style="config5[index]"
             :key="index">
          <div class="swiper-box" :style="{backgroundImage: 'url('+item.cover+')'}" style="width: 100%; height: 100%;">
            <p class="box-title">{{ item.label }}</p>
            <p class="box-tip">{{ item.remark }}</p>
          </div>
        </div>
      </div>
    </transition>
    <!--region免责声明-->
    <van-dialog v-model="showDialog" class="dialog-mzsm" :showConfirmButton="false">
      <div class="title">免责声明</div>
      <div class="content">{{ organ.disclaimer }}</div>
      <div class="btn-wrap">
        <van-button type="info" plain @click="close">取消</van-button>
        <van-button type="info" @click="confirm">确定</van-button>
      </div>
    </van-dialog>
    <!--endregion-->
    <!--region敬请期待-->
    <van-dialog v-model="showDialogXZ" class="dialog-mzsm" :showConfirmButton="false">
      <img src="../../../assets/images/home_icon.png" class="home-icon" name="home_icon"/>
      <div class="xz-text">案由制作中,敬请期待</div>
      <div class="btn-XZ">
        <van-button type="info" @click="confirmXZ">确定</van-button>
      </div>
    </van-dialog>
    <!--endregion-->
  </div>
</template>

2.逻辑部分

<script lang="ts">
import {Vue, Component} from 'vue-property-decorator';
import {Getter, Action} from 'vuex-class';
import Organ from '@/model/Organ';

@Component({
  components: {}
})

export default class HomeSwiper extends Vue {
  @Action('setLitigationFeeInfo') private setLitigationFeeInfo: any;
  @Action('setTop') private setTop: any;
  @Getter('info')
  private organ: Organ; // 机构信息
  private showDialog: boolean = false; // 免责声明
  private showDialogXZ: boolean = false; // 敬请期待(行政)
  private currentType: string = ''; // 当前的类型
  private realIndex: any;
  private tag: boolean = false;

  // 轮播图参数
  private loading: boolean = true;
  private currentIndex: number = 1; // 当前中间imgs数组中index
  private startX: any = '';
  private startY: any = '';
  private endX: any = '';
  private endY: any = '';
  private imgs: any = [];
  private previous: number = 0;
  private config5: any = [
    {
      id: 'B',
      position: 'absolute',
      width: '39%',
      height: '82%',
      top: '6%',
      left: '12%',
      opacity: 1,
      zIndex: 2,
      transition: '.4s',
      fontSize: '30px'
    },
    {
      id: 'center',
      position: 'absolute',
      width: '45%',
      height: '100%',
      top: '0px',
      left: '50%',
      marginLeft: '-22.5%',
      opacity: 1,
      zIndex: 4,
      transition: '.4s',
      fontSize: '44px',
      boxShadow: '0 0 40px 0 #3D3E45'
    },
    {
      id: 'D',
      position: 'absolute',
      width: '39%',
      height: '82%',
      top: '6%',
      left: '48.8%',
      opacity: 1,
      zIndex: 2,
      transition: '.4s',
      fontSize: '30px'
    }
  ]; // 滑出屏幕效果样式
  private timer: any; // 定时器

  public created () {
    this.addCardStyle(); // 加入样式位置的index
    // console.log('this.organ.top:', this.organ.top);
    this.imgs.length = [];
    this.imgs = this.organ.top;
    this.play();
  }

  // 自动播放
  private play () {
    this.timer = window.setInterval(() => {
      this.prev();
      // console.log('为啥要自动播放:');
    }, 5000);
  }

  // 清除定时器
  private stopPlay () {
    clearInterval(this.timer);
  }

  // 滑动上一个
  private prev () {
    // this.imgs.unshift(this.imgs.pop());
    this.config5.push(this.config5.shift());
    this.currentIndex = this.currentIndex - 1;
    if (this.currentIndex < 0) {
      this.currentIndex = this.imgs.length - 1;
    }
    this.centerIndex('prev');
  }

  // 滑动下一个
  private next () {
    // this.imgs.push(this.imgs.shift());
    this.config5.unshift(this.config5.pop());
    this.currentIndex = this.currentIndex + 1;
    if (this.currentIndex > this.imgs.length - 1) {
      this.currentIndex = 0;
    }
    this.centerIndex('next');
    // console.log(this.currentIndex);
  }

  // 开始移动端滑动屏幕
  private start (event: any) {
    this.startX = event.changedTouches[0].clientX;
    this.startY = event.changedTouches[0].clientY;
  }

  // 连续滑动
  private move (event: any) {
    this.endY = event.changedTouches[0].clientY;
    this.endX = event.changedTouches[0].clientX;
    this.stopDefault(event);
  }

  // 滑动
  private end (event: any) {
    this.endY = event.changedTouches[0].clientY;
    this.endX = event.changedTouches[0].clientX;
    this.formatSwiper();
  }

  private formatSwiper () {
    if (this.startX > this.endX) {
      // console.log('左边滑动');
      if (this.startX > this.endX + 40) {
        this.next();
      }
    } else {
      // console.log('右边滑动');
      if (this.endX > this.startX + 40) {
        this.prev();
      }
    }
  }

  // 阻止touchmove的横向默认事件(ios快捷操作会关闭页面)
  private stopDefault (event: any) {
    let differenceY = this.endY - this.startY;
    let differenceX = this.endX - this.startX;
    if (Math.abs(differenceX) > Math.abs(differenceY)) {
      event.preventDefault();
    }
  }

  // 当前imgs在位置上的index(并非img数组的index)
  private centerIndex (val: any) {
    if (val === 'prev') {
      for (let val of this.imgs) {
        if (val.index === this.imgs.length - 1) {
          val.index = 0;
        } else {
          val.index = val.index + 1;
        }
      }
    } else {
      for (let val of this.imgs) {
        if (val.index === 0) {
          val.index = this.imgs.length - 1;
        } else {
          val.index = val.index - 1;
        }
      }
    }
  }

  // 点击事件
  private chooseItem (item: any, index: any, config: any) {
    this.stopPlay(); // 关闭定时器
    /*item=> top中的每一项
    * index=> 索引 对应top中的id 0=》民事案 1=》行政案 2=》执行案
    * config=> 当前点击项对应config5里面的样式,左=》id:B 中=》id:center 右=》id:D
    * */
    // console.log('config5[index]:',config);
    if (config.id === 'B') { // 位置为0,右划一次,这里根据config样式中的id来判断当前点击项的左中右位置
      // console.log('位置为0时左:');
      this.prev();
    } else if (config.id === 'D') { // 位置为2,左滑一次
      // console.log('位置为2时右:');
      this.next();
    } else if (config.id === 'center') { // 位置在中间时,不改变
      this.showDialogMZ(index);
      // console.log('位置在中间');
    }
  }

  private addCardStyle () {
    if (this.imgs.length > 7) {
      let addtime = this.imgs.length - 7;
      for (let i = 0; i < addtime; i++) {
        this.config5.push({
          id: 'center',
          position: 'absolute',
          width: '45%',
          height: '100%',
          top: '0px',
          left: '50%',
          marginLeft: '-22.5%',
          opacity: 0,
          transition: '.1s'
        });
      }
    }
  }

  /**
   * 关闭免责声明弹窗
   */
  private close () {
    this.$utils.Log.saveEvent('3', '点击同意/取消', 'button');
    this.showDialog = false;
  }

  /**
   * 确认 免责声明
   */
  private confirm () {
    this.$utils.Log.saveEvent('3', '点击同意/取消', 'button');
    this.$emit('chooseType', this.currentType); // 展示案由
    this.$emit('goNext', false); // 展示案由
    this.setTop(this.currentType);
  }

  /**
   * 显示免责声明
   */
  private showDialogMZ (index: number) {
    let val = (this.organ.top as any).find((t: any, i: number) => index === i);
    if (val.active) {
      this.showDialog = true;
      this.currentType = val.name;
    } else {
      this.showDialogXZ = true;
    }
  }

  /**
   * 确认关闭敬请期待弹窗
   */
  private confirmXZ () {
    this.showDialogXZ = false;
  }
}
</script>

3.css

<style lang="less" scoped>
.swiper {
  width: 100%;
  height: 630px;
  position: relative;
  overflow: hidden;

  .swiper-box {
    background-size: 100%;
    background-repeat: no-repeat;
    overflow: hidden;
  }

  .box-title {
    color: #ffffff;
    line-height: 60px;
    text-align: center;
    margin-top: 350px;
  }

  .box-tip {
    font-size: 30px;
    color: #ffffff;
    line-height: 60px;
    text-align: center;
  }
}

.home-icon {
  width: 180px;
  height: 197px;
  margin: 53px 230px 0 230px;
}

.xz-text {
  font-size: 36px;
  color: #666666;
  line-height: 55px;
  text-align: center;
  margin-top: 20px;
}

.btn-XZ {
  text-align: center;
  box-sizing: border-box;
  padding-top: 50px;
  height: 170px;

  .van-button {
    width: 135px;
    height: 45px;
    border: 1px solid #1989fa;

    &:first-child {
      margin-right: 30px;
    }
  }
}
</style>

修改了判断位置的方法,增加了自动播放功能(click点击时清除定时器),参考文章为展示5个卡片的示例,这里改为了3个,config样式进行了修改

参考文章

www.jianshu.com/p/9170280de…