使用场景
一般我们开发轮播组件都是使用现成的swipe插件,但是有时候一个比较简单的轮播需求我们用几行代码就可以实现,特别是移动端的项目,这样可以减少资源包的大小。下面让我们一步一步来实现一个垂直循环轮播标签的功能,以下代码示例是用vue2编写的,掌握了实现思路,用任何语言都可以快速实现。
dom结构
首先是dom结构,我们需要一个展示当前轮播项的容器swipe,轮播项的高度和宽度与这个容器的大小一致(高度设置使用了百分比的方式实现),这样保证每次只展示一个轮播项。内部嵌套一个包裹轮播项的容器wrapper,这个容器是用来做动画轮播的。最后是遍历渲染轮播项slide,最后一个轮播项是实现循环轮播的关键。
wrapper和slide的高度设置的前提条件是轮播项大于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>