使用vue的transition动画,匹配移动端的左右触摸滑动和隐藏左右按钮等等。
效果如下所示:

整个组件的代码如下所示:
<template>
<div class="slider-container" >
<div class="img-slider-touchwindow" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
<transition name="img-slider" tag="div" :enter-class="enterClass" :leave-active-class="leaveActiveClass" :enter-active-class="enterActiveClass">
<div v-for="(item,i) in imgList" :key="i" v-if="i === (currentIndex-1)" class="img-slider-bar" >
<img :src="item.img" alt="">
</div>
</transition>
</div>
<ul ref="imgSliderDirection" class="img-slider-direction">
<li class="img-slider-direction-left" @click="pre()">
<svg class="img-slider-direction-left-icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M481.233 904c8.189 0 16.379-3.124 22.628-9.372 12.496-12.497 12.496-32.759 0-45.256L166.488 512l337.373-337.373c12.496-12.497 12.496-32.758 0-45.255-12.498-12.497-32.758-12.497-45.256 0l-360 360c-12.496 12.497-12.496 32.758 0 45.255l360 360c6.249 6.249 14.439 9.373 22.628 9.373z" /></svg>
</li>
<li class="img-slider-direction-right" @click="next()">
<svg class="img-slider-direction-right-icon" width="30px" height="30.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M557.179 904c-8.189 0-16.379-3.124-22.628-9.372-12.496-12.497-12.496-32.759 0-45.256L871.924 512 534.551 174.627c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0l360 360c12.496 12.497 12.496 32.758 0 45.255l-360 360c-6.249 6.249-14.439 9.373-22.628 9.373z" /></svg>
</li>
</ul>
<ul class="img-slider-dots">
<li v-for="(dot, i) in imgList" :key="i"
:class="{dotted: i === (currentIndex-1)}"
@click = jump(i+1)
>
</li>
</ul>
</div>
</template>
<script>
//参考 https://cn.vuejs.org/v2/guide/transitions.html
export default {
props:{
//initInterval:每张图片轮播的间隔时间,默认3秒,单位秒
initInterval:{
type:Number,
default:3
},
//imgList:需要轮播的图片集合
imgList:{
type:Array,
default:function(){
return [
{
img:'/static/images/hdimg/20120814204658.jpg'
},
{
img:'/static/images/hdimg/20200827163501.jpg'
},
{
img:'/static/images/hdimg/20200827163502.jpg'
},
{
img:'/static/images/hdimg/20120814204733.jpg'
},
{
img:'/static/images/hdimg/20200827163503.jpg'
},
]
}
}
},
data(){
return {
currentIndex:1,//当前显示图片的位置
direction:-1, //-1从左向右,1从右向左
timer:null, //轮播的定时器
flag: true, // 节流阀 防止快速滑动
startX: 0, // 手指开始触摸位置
moveX: 0, // 手指移动距离
}
},
computed: {
enterClass:function(){
return this.direction===-1?"img-slider-enter-left-to-right":"img-slider-enter-right-to-left";
},
leaveActiveClass:function(){
return this.direction===-1?"img-slider-leave-active-left-to-right":"img-slider-leave-active-right-to-left";
},
enterActiveClass:function(){
return "img-slider-enter-active-all";
},
interval:function(){
return this.initInterval*1000;
},
isMobile(){
return navigator.userAgent.toLowerCase().match(/(ipod|ipad|iphone|android|coolpad|mmp|smartphone|midp|wap|xoom|symbian|j2me|blackberry|wince)/i) != null;
}
},
methods:{
pre(){
var currentIndex=(this.currentIndex-1)<=0?this.imgList.length:(this.currentIndex-1)
this.animate(currentIndex,1);
},
next(){
var currentIndex=(this.currentIndex+1)>this.imgList.length?1:(this.currentIndex+1)
this.animate(currentIndex,-1);
},
jump(idx){
this.animate(idx,this.currentIndex<idx?-1:1);
},
animate(index, imgDirection) {
if (this.timer) {
window.clearInterval(this.timer);
this.timer = null ;
}
this.direction=imgDirection;
this.currentIndex=index;
this.timer = window.setInterval(() => {
this.currentIndex=this.currentIndex+1>this.imgList.length?1:(this.currentIndex+1);
this.direction=-1;
}, this.interval);
},
play() {
if (this.timer) {
window.clearInterval(this.timer)
this.timer = null
}
this.timer = window.setInterval(() => {
this.currentIndex=this.currentIndex+1>this.imgList.length?1:(this.currentIndex+1);
this.animate(this.currentIndex,this.direction);
}, this.interval);
},
stop() {
window.clearInterval(this.timer)
this.timer = null
},
init() {
this.play()
window.onblur = function() { this.stop() }.bind(this)
window.onfocus = function() { this.play() }.bind(this)
},
touchstart(event){// 手指开始触摸事件
window.clearInterval(this.timer); // 关闭自动轮播
this.startX = event.targetTouches[0].clientX; // 获取开始触摸位置
},
touchmove(event){// 手指开始移动
this.moveX = event.targetTouches[0].clientX - this.startX; // 手指移动位置
},
touchend(event){// 结束触摸
if(this.moveX>10)
this.pre();
else if(this.moveX<-10)
this.next();
}
},
mounted(){
this.init();
this.$nextTick(function(){
//console.log(this.isMobile);
if(this.isMobile){
this.$refs.imgSliderDirection.style.display="none";
}
});
}
}
</script>
<style lang="scss" scoped>
.slider-container{
100%;
height:100%;
overflow: hidden;
margin:0 auto;
position: relative;
}
.img-slider-touchwindow{
100%;
height:100%;
position: relative;
}
.img-slider-bar{
100%;
height:100%;
position:absolute;
top:0;
left:0;
}
.img-slider-bar img{
100%;
height:100%;
object-fit: cover;
}
.img-slider-enter-active-all{
transition: all 1s;
}
.img-slider-leave-active-left-to-right {
transition: all 1s;
transform: translateX(-100%);
}
.img-slider-leave-active-right-to-left {
transition: all 1s;
transform: translateX(100%);
}
.img-slider-enter-left-to-right {
transform: translateX(100%);
}
.img-slider-enter-right-to-left {
transform: translateX(-100%);
}
ol,ul{
list-style: none;
}
.img-slider-direction-left, .img-slider-direction-right{
position:absolute;
top:50%;
transform:translateY(-50%);
50px;
height:50px;
background-color:rgba(0,0,0,.3);
border-radius:50%;
cursor:pointer;
}
.img-slider-direction-left{
left:3%;
padding-left:12px;
padding-top:10px;
}
.img-slider-direction-right{
right:3%;
padding-right:12px;
padding-top:10px;
}
.img-slider-dots{
position:absolute;
bottom:10px;
left:50%;
transform:translateX(-50%);
}
.img-slider-dots li{
display:inline-block;
15px;
height:15px;
margin:0 3px;
border:1px solid white;
border-radius:50%;
background-color:#333;
cursor:pointer;
}
.img-slider-dots .dotted{
background-color:orange;
}
</style>