vue 轮播

223 阅读1分钟

父组件

<template>
  <div class="swipe-demo">
   <ui-swipe :imgList="imgList">
      <div
        v-for="(item, ind) in imgList"
        :key="ind"
        @click="handleClick(item)"
        class="swiper-img"
      >
        <img :src="item.picUrl" />
      </div>
    </ui-swipe>
  </div>
</template>

<script>
export default {
  name: "swipe-demo",
  data() {
    return {
      imgList: [
        {
          picUrl: require("../../../assets/components/list-3.png"),
          picLink: "https://baidu1.com",
        },
        {
          picUrl: require("../../../assets/components/list-3.png"),
          picLink: "https://baidu2.com",
        },
        {
          picUrl: require("../../../assets/components/list-3.png"),
          picLink: "https://baidu3.com",
        },
        {
          picUrl: require("../../../assets/components/list-3.png"),
          picLink: "https://baidu1.com",
        },
        {
          picUrl: require("../../../assets/components/list-3.png"),
          picLink: "https://baidu2.com",
        },
        {
          picUrl: require("../../../assets/components/list-3.png"),
          picLink: "https://baidu3.com",
        },
      ],
    };
  },
  mounted() {},
  methods: {
    handleClick(val) {
      console.log(val);
    },
  },
};
</script>

<style lang="scss">
.swipe-demo {
  font-size: 24px;
}
</style>

子组件

<template>
  <div
    class="ui-swiper"
    @touchstart="onTouchStart"
    @touchend="onTouchEnd"
    :style="{ height: height }"
  >
    <div :style="[ulStyle, swiperStyle]" class="swiper-box">
      <slot></slot>
    </div>
    <div
      v-if="options.swiperNumShow"
      :class="[options.swiperNum == '' ? 'swiper-num' : 'swiper-num-size']"
    >
      <span class="swiper-num-style">{{ index + 1 }}</span
      ><span class="swiper-num-style2">/{{ imgList.length }}</span>
    </div>
    <div v-if="options.arrowShow">
       <img
      class="ui-swiper-right"
      src="../../assets/components/arrow_right.png"
      alt=""
      @click="$_onRight"
    />
    <img
      class="ui-swiper-left"
      src="../../assets/components/arrow_left.png"
      alt=""
      @click="$_onLeft"
    />
    </div>
   

    <div v-show="options.showDots" class="swiper-dots">
      <div
        v-for="(item, ind) in imgList"
        :key="ind"
        :class="[
          options.dotsType == 'rect' ? 'dots-item-box' : 'dots-item',
          index === ind ? 'active' : '',
        ]"
      ></div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      ulStyle: { width: screen.width }, // 轮播图容器宽度
      itemWidth: screen.width, // 单个轮播图容器的宽度,默认屏幕宽度,
      swiperStyle: {}, // 控制轮播的样式
      index: 0, // 当前显示的轮播图索引,默认第一张
      touchStart: {}, // 触摸开始点位
      touchEnd: {}, // 触摸结束点位
      intervalTime: "", // 循环轮播定时器
    };
  },
  props: {
    height: {
      type: String,
      default: "200px",
    },
    options: {
      type: Object,
      default() {
        return {
          showDots: true, // 是否显示分页器
          interval: 5000, // 轮播间隔时间,默认5  s
          autoplay: true, // 是否自动播放
          swiperNumShow: false, //是否显示图片数字
          dotsType: "dot", //dot圆点rect长方形
          swiperNum: "", //图片数字格式 默认空 num表示左大右小
          arrowShow:false,
        };
      },
    },
    imgList: {
      type: Array,
    },
  },
  mounted() {
    this.calcWidth();
    this.handleLoopMove();
  },
  methods: {
    calcWidth() {
      this.$nextTick(function () {
        let length = this.imgList.length;
        this.ulStyle.width = parseInt(this.itemWidth * length) + "px"; // 容器总宽度
      });
    },
    ///移动处理
    handleMove() {
      let moveX = this.itemWidth * this.index;
      if (this.index === 0) {
        moveX = 0;
      }
      this.swiperStyle = {
        transform: "translateX(-" + moveX + "px)",
      };
    },
    //循环移动处理
    handleLoopMove() {
      // 当设置自动播放时,执行自动循环播放操作,否则,只执行下一次轮播效果
      if (this.options.autoplay) {
        let interval = this.options.interval ? this.options.interval : 5000;
        let len = this.imgList.length;
        this.intervalTime = setInterval(() => {
          if (
            this.index == this.imgList.length - 1 ||
            len != this.imgList.length
          ) {
            this.index--;

            if (this.index == 0) {
              len = this.imgList.length;
            } else {
              len--;
            }
          } else if (len == this.imgList.length) {
            this.index++;
          }
          this.handleMove();
        }, interval);
      }
    },
    // 触摸开始事件,记录下触摸点
    onTouchStart(e) {
      this.touchStart = e.changedTouches[0]; // 记录开始触摸点
      // 清除定时器
      clearInterval(this.intervalTime);
    },
    // 触摸结束事件,记录下触摸点,比较当前点和触摸开始点,判断触摸方向
    onTouchEnd(e) {
      this.touchEnd = e.changedTouches[0];
      // 比较移动的点位差,正数就是右滑,负数就是左滑
      if (this.touchEnd.clientX - this.touchStart.clientX > 60) {
        this.index--;
        if (this.index <= 0) {
          this.index = 0;
        }
      } else if (this.touchEnd.clientX - this.touchStart.clientX < -60) {
        this.index++;
        if (this.index >= this.imgList.length - 1) {
          this.index = this.imgList.length - 1;
        }
      }
      // 处理当前的滑动
      this.handleMove();
      // 同时开启自动轮播
      this.handleLoopMove();
    },
    $_onLeft(){
      if(this.index >0 && this.index<this.imgList.length){
        this.index--;
        this.handleMove();
      }
    },
    $_onRight(){
      if(this.index >=0 && this.index<this.imgList.length-1){
        this.index++;
        this.handleMove();
      }
    }
  },
  watch: {
    imgList: function (e) {
      this.calcWidth();
    },
  },
  destroyed() {
    // 清除定时器
    if (this.autoplay) {
      clearInterval(this.intervalTime);
    }
  },
};
</script>
<style lang="scss">
.ui-swiper {
  overflow: hidden;
  position: relative;
  .swiper-box {
    white-space: nowrap;
    height: 100%;
    transition: 0.5s ease;
    display: flex;
    .swiper-img {
      list-style: none;
      height: 100%;
      width: 100%;
      overflow: hidden;
      img {
        width: 100%;
        height: 100%;
      }
      &.zoom {
        transition: 0.5s ease;
      }
    }
  }
  .swiper-num {
    position: absolute;
    bottom: 20px;
    right: 20px;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    padding: 5px 15px;
    border-radius: 25px;
    font-size: 24px;
  }
  .swiper-num-size {
    position: absolute;
    top: 20px;
    right: 20px;
    .swiper-num-style {
      font-size: 36px;
    }
    .swiper-num-style2 {
      font-size: 28px;
      color: #9ba0aa;
    }
  }

  .swiper-dots {
    position: absolute;
    bottom: 16px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    .dots-item {
      width: 15px;
      height: 15px;
      border-radius: 50%;
      background: rgba(0, 0, 0, 0.3);
      margin: 0 4px;
      &.active {
        background: #409eff;
      }
    }
    .dots-item-box {
      width: 20px;
      height: 5px;
      background: rgba(0, 0, 0, 0.3);
      margin: 0 4px;
      &.active {
        background: #409eff;
      }
    }
  }
  .ui-swiper-right {
    position: absolute;
    top: 40%;
    right: 3%;
  }
  .ui-swiper-left {
    position: absolute;
    top: 40%;
    left: 3%;
  }
}
</style>