vue轮播图(可随父元素高宽自适应)

使用vue的transition动画,匹配移动端的左右触摸滑动和隐藏左右按钮等等。

效果如下所示:

vue轮播图(可随父元素高宽自适应)

整个组件的代码如下所示:

<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>