循环轮播的简单实现

733 阅读2分钟

使用场景

一般我们开发轮播组件都是使用现成的swipe插件,但是有时候一个比较简单的轮播需求我们用几行代码就可以实现,特别是移动端的项目,这样可以减少资源包的大小。下面让我们一步一步来实现一个垂直循环轮播标签的功能,以下代码示例是用vue2编写的,掌握了实现思路,用任何语言都可以快速实现。

dom结构

首先是dom结构,我们需要一个展示当前轮播项的容器swipe,轮播项的高度和宽度与这个容器的大小一致(高度设置使用了百分比的方式实现),这样保证每次只展示一个轮播项。内部嵌套一个包裹轮播项的容器wrapper,这个容器是用来做动画轮播的。最后是遍历渲染轮播项slide,最后一个轮播项是实现循环轮播的关键。

wrapperslide的高度设置的前提条件是轮播项大于1,如果是一个则无需加1

<div class="swipe" v-if="items && items.length">
    <div 
        class="wrapper"
        :style="{height: `${(items.length + 1) * 100}%`}"
        
    >
        <div 
            class="slide" 
            v-for="item in items" 
            :key="item"
            :style="{height: `${1 / (items.length + 1) * 100}%`}"
        >{{ item }}</li>
        
        <!-- 最后添加一个跟第一个轮播项相同的内容,这个轮播完后立马切换到第一个轮播项,这样就可以实现无缝的循环轮播 -->
        <div class="slide" v-if="items.length > 1">{{ items[0] }}</li>
    </div>
</div>

样式部分

样式部分比较简单

.swipe {
  width: 40px;
  height: 16px;
  line-height: 16px;
  overflow: hidden;
  background: #f66304;

  .wrapper {
    transition-timing-function: ease-out; /* 可自由选择移动过渡效果 */

    .slide {
      color: #fff;
      text-align: center;
      font: bolder 12px/normal PingFangSC-Semibold;
    }
  }
}

动画实现

轮播是通过设置wrapper的Y轴偏移高度来实现的,当轮播到最后一个项的时候,记得在过渡完成后立马回到第一个轮播项。

export default {
  name: 'my-swipe',
  props: {
    items: {
      type: Array,
      default: [],
      require: true
    },
    // 一个标签的轮播时长
    duration: {
      type: Number,
      default: 1000
    },
    // 一个标签轮播的停顿时长
    pauseDuration: {
      type: Number,
      default: 800
    }
  },
  data() {
    return {
      slideIndex: 0, // 当前轮播到第几个轮播项
      translateY: 0, // 标签容器垂直方向上的偏移
      slideDuration: 0 // 标签滑动的过渡时间
    }
  },
  mounted() {
      this.start()
  },
  methods: {
    start() {
      const change = () => {
          setTimeout(() => { // 设置setTimeout,是为了暂停一会才开始过渡动画
              const slideHeight = `${1 / (this.tags.length + 1) * 100}%`
              this.slideIndex++
              this.slideDuration = this.duration
              this.translateY = `-${parseFloat(slideHeight) * this.slideIndex}%`
              
              if (this.slideIndex === this.tags.length) {
                  setTimeout(() => {
                    // 轮播到最后一个标签(也就是第一个标签的内容)结束后去除过渡,立马变换到第一个标签的位置
                    this.slideIndex = 0
                    this.slideDuration = 0
                    this.translateY = 0
                  }, this.duration)
              }
          })
      }

      change()
      setInterval(change, this.duration + this.pauseDuration)
    }
  }
}

此时dom结构的wrapper需要添加transform相关的style


    <div 
        class="wrapper"
        :style="{
            height: `${(items.length + 1) * 100}%`,
            transform: `translate3d(0, ${translateY}, 0)`, 'transition-duration': `${slideDuration}ms`
        }"
    >
       
    </div>