需求分析
- Slides组件通常包括一下功能:
- 可支持自动播放
- 可设置自动播放时间
- 轮播图片高宽可自适应
- 支持触屏滑动轮播
- 可无缝轮播
方法实现
1、定义组件:
在html中定义
t-slides组件定义为最外层轮播图包裹器,t-slides-item组件包裹每张轮播图片,并且每个t-slides-item组件都声明一个name,用以标识每张图片。
<t-slides class="wrapper"
:autoPlay="autoPlay"
:selected.sync="selected">
<t-slides-item name="1">
<div class="box">1</div>
</t-slides-item>
<t-slides-item name="2">
<div class="box">2</div>
</t-slides-item>
<t-slides-item name="3">
<div class="box">3</div>
</t-slides-item>
</t-slides>
2、基础功能逻辑 :
t-slides单文件组件中的template模板声明相应鼠标、touch事件。并声明一个solt插槽用以接收t-slides-item组件数据,这些数据在我们做轮播动画的时候会用到,稍后我们再聊它们。
t-slides-dots类里面的内容为左右点击切换与显示轮播图下标圆点相关功能。
<template>
<div @mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
@touchend="onTouchEnd"
@touchstart="onTouchStart"
class="t-slides">
<div class="t-slides-window" ref="window">
<div class="t-slides-wrapper">
<slot></slot>
</div>
</div>
<div class="t-slides-dots">
<span @click="onClickPrev" data-action="prev">
<t-icon name="left"></t-icon>
</span>
<span v-for="n in childrenLength" :class="{active: selectedIndex === n-1}"
:key="n" :data-index="n-1"
@click="select(n-1)">
{{n}}
</span>
<span @click="onClickNext" data-aciton="next">
<t-icon name="right"></t-icon>
</span>
</div>
</div>
</template>
通过计算属性找到this.$children名字等于t-sildes-item的组件数量,这样就等于获取到了图片的数量,从而可执行与数量相关的逻辑。
computed: {
items() {
return this.$children.filter(vm=>vm.$options.name === 't-sildes-item')
}
},
3、自动轮播逻辑:
定义一个方法,用setTimeout模拟setInterval并给setTimeout一个id,在页面生命周期销毁前或者任何时候关掉它,这样可减少性能消耗。有了这个方法自动轮播就很简单了,mounted的时候执行一下。
playAutomatically() {
if (this.timeId) {return}
let run = () => {
let index = this.names.indexOf(this.getSelected())
let newIndex = index + 1
this.select(newIndex) //告诉外界选中的 newIndex
this.timeId = setTimeout(run, this.autoPlayDelay) //this.autoPlayDelay 时间间隔
}
this.timeId = setTimeout(run, this.autoPlayDelay)
},
4、touch模拟滑动逻辑:
定义touch开始事件结束事件,拿到touch数组的第一项(第一个手指),取出XY轴坐标。用Math算出开始横坐标与结束横坐标的角度(三角函数最小边不超过斜边的2倍),则角度不会大于30°,角度不大于30°,我们就可以理解用户是在执行滑动操作。
onTouchEnd(e) {
let endTouch = e.changedTouches[0]
let {clientX: x1, clientY: y1} = this.startTouch
let {clientX: x2, clientY: y2} = endTouch
let distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
let deltaY = Math.abs(y2 - y1)
let rate = distance / deltaY
if (rate > 2) {
if (x2 > x1) {
this.select(this.selectedIndex - 1)
} else {
this.select(this.selectedIndex + 1)
}
}
this.$nextTick(()=> {
this.playAutomatically()
})
},
5、t-slides-item组件无缝轮播相关css:
通过animationEnabled变量控制轮播始终保持2种状态:1、当前状态 2、离开状态。
当前状态执行当前状态的样式类,离开状态执行另一种样式类。这样我们只需要定义两种样式类即可做出向左向右的任意动效样式。
6、轮播图片高宽可自适应:
只需要在当前状态类.slide-leave-active中定义position: absolute; width:100%; height: 100%;
其中微妙可自行琢磨。
<template v-if="animationEnabled">
<transition name="slide">
<div class="t-slides-item" v-if="visible" :class="{reverse}">
<slot></slot>
</div>
</transition>
</template>
<template v-else>
<div class="t-slides-item" v-if="visible" :class="{reverse}">
<slot></slot>
</div>
</template>
<style lang="scss" scoped>
.slide-leave-active {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.slide-enter-active, .slide-leave-active {
transition: all 0.5s;
}
.slide-enter {
transform: translateX(100%);
}
.slide-enter.reverse {
transform: translateX(-100%);
}
.slide-leave-to {
transform: translateX(-100%);
}
.slide-leave-to.reverse {
transform: translateX(100%);
}
</style>