无缝轮播图Vue2 轮播图组件可拖拽无缝切换

此轮播图在普通轮播图的基础上优化,增加第一张切上一张接最后一张,最后一张切下一张接第一张,且无缝衔接的功能。增加拖拽切换功能;

原理

1.排版

轮播图分三层结构。最外层相对定位并且配合css样式溢出隐藏,使轮播图视口只能显示一张图片。轮播图第二层为可移动元素,配合css绝对定位并且使用css3过度效果实现切换时的动画。第三层是轮播图的各个图片,这里让每一个子项的display属性值是inline-block。让其父级的font-zise:0;消除内联块受字体大小影响而不在一条直线上(既inline-bolock元素受font-size其vertical-align的影响排版)。再让其父元素white-space: nowrap;让所有子项不换行。

计算轮播图视口的宽度,令每个轮播子项宽度和视口宽度一致。这样显示的张数的style left的值和第n张绑定。

2.无缝衔接

在第一张前面复制最后一张的拷贝,在最后一张复制第一张的拷贝。默认显示最终的第二张(实际上是第一张)

比如轮播图传入三张图片,分别是图片一、二、三。则轮播图初始状态如下图;

当轮播图显示的是第一张,此时切上一张时。会切到3拷贝这一张,并在切换完成后迅速变为第三张(这里控制css样式使过度失效)。这样肉眼看上去就是1无缝切到3。同理3切到1时也一样。

3.拖拽切换

记录鼠标点下去时候的x值,和抬起来的值只差。如果超过一定范围则调用轮播切换的方法即可。

4.自动轮播

略..

代码

使用引入组件

<template>
  <div id="app">
    <mySwiper :imgArr="imgArr"/>
  </div>
</template>
<script>
import mySwiper from './components/MySwiper'
export default {
  name: 'App',
  data(){
    return {
      imgArr:[
        require('./assets/images/1.jpg'),
        require('./assets/images/2.jpg'),
        require('./assets/images/3.jpg'),
        require('./assets/images/4.jpg'),
      ]
    }
  },
  components: {
    mySwiper
  }
}
</script>
<style>
</style>

组件代码

html

<template>
<div>
  <!-- 轮播图 -->
  <div class="swiper" ref="swip" @mousedown="seipBodyMouseDowen($event)" @mouseleave="mLeave" @mouseenter="mEnter">
    <!-- 可移动的轮播图盒子 -->
    <div class="swiperBody" :style="{
      'left': trueLeft + 'px',
      'transition': runtime && jb ?  'left 1s ease' : 'none'
    }">
    <!-- 图片位置 -->
        <template v-for="item,index in imgArr1">
            <div class="sitem" :style="{
              'backgroundImage':'url('+item+')',
              'width':swipWidth+'px'}" 
              :key="index"></div>
        </template>
    </div>
    <!-- 小圆点 -->
      <div class="pointer" ref="pointer">
        <template v-for="item,index in imgArr">
          <span class="span" :class="{'active': runNun1==index}" :key="index" @click="setSwip(index)"></span>
        </template>
      </div>
  </div>
  <!-- 切换按钮(测试) -->
  <button  @click="run('-')">上一张</button>
  <button @click="run('+')">下一张</button>
</div>
</template>

js

<script>
  export default {
    name: 'MySwiper',
    data(){
        return {
            timmer1: null,//该定时器配合runtime使用
            timmer2: null,//自动轮播
            runtime:false,//避免短时间内多次重复点击
            imgArr1:[],//使用imgArr1重新编排传入的imgArr图片数组,用于无缝衔接切换
            runNun: 0,//
            runNun1: 0,//用于控制小圆点聚焦(如果使用runNun则无缝衔接时聚焦有延迟)
            swipWidth: 0,//轮播图宽度
            trueLeft: 0,//
            muveNum: 0,//鼠标每次拖拽的距离
            jb: true//无缝衔接时的不需要动画
        }
    },
    props: {
      imgArr:{
        type: Array,
        require: true,
      }
    },
    computed:{
      computLeft(){
          return - this.swipWidth * (this.runNun+1);
      }
    },
    beforeMount(){
      // 无缝衔接精髓
      this.imgArr1 = this.imgArr.concat([]);
      this.imgArr1.push(this.imgArr[0]);
      this.imgArr1.unshift(this.imgArr[this.imgArr.length-1]);
    },
    mounted(){
      this.swip = this.$refs.swip;
      this.swipWidth = this.swip.offsetWidth;
      document.addEventListener('mouseup',this.mouseupControl)

      this.swiperAuto();
    },
    methods:{
      run(tag){//切换
        this.jb = true;
        if(this.runtime) return;
        if(tag=='+'){//下一张
          this.runNun++;
          this.runNun1++;
          if(this.runNun==this.imgArr.length){//最后一张
            this.runNun1 = 0;
            setTimeout(()=>{//无缝精髓
              this.jb = false;
              this.runtime = false;
              this.runNun = 0;
            },1000);
            // 
          }
        }else if(tag=='-'){//上一张
          this.runNun--;
          this.runNun1--;
          if(this.runNun==-1){//第一张
            this.runNun1 = this.imgArr.length-1;
            setTimeout(()=>{//无缝精髓
              this.jb = false;
              this.runtime = false;
              this.runNun = this.imgArr.length-1;
            },1000);
          }
        }else{
           this.trueLeft = this.computLeft;
           this.runTimeControl();
        }
      },
      setSwip(index){//点击小圆点
        this.runNun = index;
        this.runNun1 = index;
      },
      seipBodyMouseDowen(e){//拖拽切换
        if(this.runtime){
          this.swip.onmousemove = null;
          return '';
        }
        var dowenPositionX = e.screenX;
        this.swip.onmousemove = (e1)=>{

          var movePositionX = e1.screenX;
          this.muveNum = movePositionX - dowenPositionX;
          this.trueLeft = this.computLeft + this.muveNum;
        }
      },
      runTimeControl(){//轮播图动画切换中
        this.runtime = true;
        clearTimeout(this.timmer1);
        this.timmer1 = setTimeout(()=>{
          this.runtime = false;
        }, 1000);
      },
      mouseupControl(){
        this.swip.onmousemove = null;
        if(this.muveNum>0 && this.muveNum > this.swipWidth*0.2){
          this.run('-')
        }else if(this.muveNum < 0 && this.muveNum*-1 > this.swipWidth*0.2){
          this.run('+')
        }else{
           this.run()
        }
      },
      mLeave(){
       this.swiperAuto();
      },
      mEnter(){
        clearInterval(this.timmer2);
      },
      swiperAuto(){
        this.timmer2 = setInterval(()=>{
          this.run('+')
        },3500);
      }
    },
    beforeDestroy(){
      document.onmouseup = null;
    },
    watch:{
      computLeft(newVal){//使用trueLeft控制轮播图而不是computLeft,是因为拖拽时会冲突
        this.trueLeft = newVal;
        this.runTimeControl();
      }
    }
  }
</script>

css

<style scoped>
  .swiper{
    position: relative;
    width: 100%;
    margin: 20px auto;
    height: 400px;
    overflow: hidden;
    border: 1px solid #ccc;
    box-sizing: border-box;
    user-select: none;
  }
  .swiperBody{
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    white-space: nowrap;
    min-width: 100%;
  }
  .swiperBody .sitem{
    display: inline-block;
    height: 100%;
    background-position: center center;
    background-origin: padding-box;
    background-size: 100% 100%;
    background-repeat: no-repeat;
  }
  .pointer{
    height: 6px;
    width: 100%;
    position: absolute;
    left: 0;
    bottom: 20px;
    z-index: 2;
    text-align: center;
    font-size: 0;
  }
  .pointer .span{
    display: inline-block;
    width: 12px;
    height: 12px;
    background-color: #fff;
    border-radius: 50%;
    margin: 0 10px;
    cursor: pointer;
  }
  .pointer .span.active{
    background-color: rgb(248, 123, 7);
  }
</style>

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue实现轮播图的滑动和无缝功能,可以参考以下步骤: 1. 首先,在data中定义需要用到的状态,如轮播图的计数器、移动距离等。\[1\] 2. 在mounted钩子函数中,初始化轮播图插件,如使用Swiper插件,可以在swiper()方法中进行初始化设置。设置autoplay为true,loop为true,slidesPerView为需要同时展示的图片数量,spaceBetween为图片之间的间距。\[2\] 3. 添加window.onresize事件,监听浏览器窗口变化。当窗口变化时,重新获取轮播图的宽度,以便计算移动位置的准确性。\[3\] 4. 在触摸事件中,记录触摸开始的坐标,并计算滑动的距离。根据滑动的距离判断是移动到下一张图片还是维持当前图片。 5. 在触摸结束事件中,根据滑动的距离和触摸开始的坐标,判断是否需要切换到下一张或上一张图片。 通过以上步骤,你可以实现Vue中的轮播图滑动和无缝功能。 #### 引用[.reference_title] - *1* *3* [vue实现轮播图](https://blog.csdn.net/yintao1989/article/details/126333077)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [使用swiper插件在vue项目中完成无缝滚动以及轮播图](https://blog.csdn.net/lll19960406/article/details/125771548)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值