用 vue 手写一个h5.页面的轮播图


直接上代码:

<template>
  <div
    id="hy-swiper"
    @touchstart="touchStart"
    @touchmove="touchMove"
    @touchend="touchEnd"
  >
    <div class="swiper">
      <div v-for="item in banners" class="swiper-item">
        <a :href="item.link"><img :src="item.image" alt="" /></a>
      </div>
    </div>
    <div class="swiper-circle">
      <ul>
        <li
          v-for="(item, index) in swiperItemCount"
          :class="currentIndex == item ? 'swiperItemActive' : ''"
          @click="clickItem(item)"
        ></li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  name: "Swiper",
  props: {
    banners: {
      // 图片内容
      type: Array,
      default() {
        return [];
      },
    },
  },
  data() {
    return {
      swiperItemCount: 0, // 轮播图数
      swiperStyle: "", // swiper的样式
      currentIndex: 1, // 当前的 index
      moveRatio: 0.25, // 跳转下一张图片所需的移动距离比例
    };
  },
  methods: {
    // 设置滚动位置
    setTransform(position) {
      this.swiperStyle.transform = `translate3d(${position}px, 0, 0)`;
      this.swiperStyle[
        "-webkit-transform"
      ] = `translate3d(${position}px), 0, 0`;
      this.swiperStyle["-ms-transform"] = `translate3d(${position}px), 0, 0`;
    },
    // 设置滚动过渡动画
    setTransition() {
      this.swiperStyle.transition = `transform 300ms`;
    },

    // 1.先操作 dom 元素
    handleDom() {
      // 获取 dom 对象
      let swiper = document.querySelector(".swiper");
      this.swiperItemCount = swiper.children.length;
      // 复制第一张图片和最后一张图片,分别放在最后面和最前面
      let nodeFirst = swiper.children[0].cloneNode(true);
      let nodeLast = swiper.children[this.swiperItemCount - 1].cloneNode(true);
      swiper.appendChild(nodeFirst); // 如果 cloneNode 报错,那么只能在 dom 中直接添加最后一个图片了
      swiper.insertBefore(nodeLast, swiper.children[0]);
      this.swiperStyle = swiper.style;
      this.totalWidth = swiper.offsetWidth;

      // 此时,currentIndex 的初始值为 1 ,那么先显示第二张图片
      this.setTransform(-this.currentIndex * this.totalWidth);
    },

    // 2. 实现用户触摸移动,图片也跟随移动,并根据滑动的方向跳转下一张图片的功能
    //触摸开始
    touchStart: function (e) {
      // 停止定时器
      this.stopTimer();

      // 获取并保存开始触摸的位置
      this.startX = e.touches[0].pageX;
    },
    // 触摸过程
    touchMove(e) {
      // 计算出用户拖动的距离
      this.currentX = e.touches[0].pageX;
      this.distance = this.currentX - this.startX;
      let currentPosition = -this.currentIndex * this.totalWidth;
      let moveDistance = this.distance + currentPosition;

      // 设置当前的位置,也就是随着触摸移动,图片也跟随移动
      this.setTransform(moveDistance);
    },
    // 触摸结束,根据滑动的方向跳转下一张图片
    touchEnd: function (e) {
      let distance_abs = Math.abs(this.distance);

      if (this.distance == 0) {
        return;
      } else if (
        this.distance < 0 &&
        distance_abs >= this.moveRatio * this.totalWidth
      ) {
        this.currentIndex++;
      } else if (
        this.distance > 0 &&
        distance_abs >= this.moveRatio * this.totalWidth
      ) {
        this.currentIndex--;
      }

      this.setTransition();
      this.setTransform(-this.currentIndex * this.totalWidth);
      this.currentScroll();

      this.swiperAuto();
    },

    // 3.判读第一张和最后一张图片的逻辑滚动,设置正确的滚动,抽取为函数
    currentScroll() {
      if (this.currentIndex == this.swiperItemCount + 1) {
        this.currentIndex = 1;
      } else if (this.currentIndex == 0) {
        this.currentIndex = this.swiperItemCount;
      }
      setTimeout(() => {
        this.swiperStyle.transition = "0ms";
        this.setTransform(-this.currentIndex * this.totalWidth);
      }, 300);
    },

    // 4. 实现点击小圆圈跳转相应的图片
    clickItem(item) {
      this.stopTimer();
      this.currentIndex = item;
      this.setTransform(-this.currentIndex * this.totalWidth);

      this.swiperAuto();
    },

    // 5.设置定时器,实现轮播功能
    swiperAuto() {
      this.playTimer = setInterval(() => {
        this.currentIndex++;
        this.setTransition();
        this.setTransform(-this.currentIndex * this.totalWidth);
        this.currentScroll();
      }, 2000);
    },
    stopTimer() {
      clearInterval(this.playTimer);
    },
  },
  mounted() {
    // 由于网络请求的图片存在时间延迟,所以等 0.5s 让图片渲染出来
    setTimeout(() => {
      this.handleDom();
      this.swiperAuto();
    }, 500);
  },
};
</script>

<style lang="less">
#hy-swiper {
  position: relative;
  overflow: hidden;
  .swiper {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;

    // transform: translateX(-375px);
    div {
      float: left;
      width: 100%;
      flex-shrink: 0; //收缩因子为0 则可以使得所有图片在同一行显示
      img {
        width: 100%;
      }
    }
  }
  .swiper-circle {
    position: absolute;
    bottom: 10px;
    left: 50%;
    transform: translate(-50%, 0);
    ul li {
      list-style: none;
      float: left;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      margin: 0 5px;
      background-color: #fff;
    }
    .swiperItemActive {
      background-color: var(--color-tint);
    }
  }
}
</style>

由于手机端是触摸滑动的,因此与 pc 端略有不同,但是思路是一样的。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM