使用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{ width:100%; height:100%; overflow: hidden; margin:0 auto; position: relative; } .img-slider-touchwindow{ width:100%; height:100%; position: relative; } .img-slider-bar{ width:100%; height:100%; position:absolute; top:0; left:0; } .img-slider-bar img{ width: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%); width: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; width: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>