VUE封装轮播图

readme

```javascript
//走马灯组件  轮播图:

index1.vue:   (隐入隐出形式)
    /* 实现思路:  :class="{ fade: index === i }" 对当前显示
       图片动态绑定一个fade属性:
       .fade {
        opacity: 1;
        z-index: 1;
      }
      实现隐入隐出 */
       

index2.vue:   (无缝衔接形式)
    /* 实现思路: 
 <ul  :style="{width: width*(lang+1) +'px',left:`-${leftVal}px`,transition:`${ition}s`}"  >
      <li v-for="(item, i) in list" :key="i"  :style="{  width: width + 'px' }">
        <img :src="item.imgUrl" alt="" />
      </li>
       <!-- 复制第一张放到最后,以实现无缝无线循环滚动效果 -->
       <li class="carousel-item" :style="{width: width +'px'}">
        <img :src="list[0].imgUrl" alt="">
      </li>
</ul>
   1、首先复制列表第一个放到最后,以实现无缝滚动的效果:
   2、leftVal是左侧位置,ition是动画时间  通过不同的这两个值 实现不同时间的滚动 */


二者使用方法完全相同:

1、引入:
import Carousel from '@/components/Carousel/index.vue'
2、使用:
<Carousel :height="300" :width="500" :list="list" :autoplay="true" :duration="5"></Carousel>
参数说明:{
    width: Number,    //宽度
    height: Number,   //高度
    list: Array,      //图片列表
    autoplay:Boolean, //是否自动播放
    duration:Number   //自动播放时间   单位(s)
}

index1.vue

<script setup>
import { ref, computed, watch,onUnmounted } from "vue";
import {throttle} from '@/utils/DebounceAndthrottle.js'
const props = defineProps({
  width: Number,
  height: Number,
  list: Array,
  autoplay:Boolean,
  duration:Number
});

//当前图片索引:
const index = ref(0);
//左边按钮
const prev = throttle(() => {
  index.value--;
  if (index.value < 0) {
    index.value = lang.value - 1;
  }
},1000);
//右边按钮:
const next = throttle(() => {
  index.value++;
  if (index.value > lang.value - 1) {
    index.value = 0;
  }
},1000);
// 计算图片列表的长度
const lang = computed(() => {
  return props.list.length;
});
//点击指示器:
const clickindex = (i) => {
  index.value = i;
};

// 封装一个自动轮播的函数
const timer = ref(null);
const autoplayFn = () => {
  // 防止触发多个定时任务
  clearInterval(timer.value);
  timer.value = setInterval(() => {
    index.value += 1;
    if (index.value > lang.value - 1) {
      // 超过右侧范围,从头开始
      index.value = 0;
    }
  }, props.duration * 1000);
};
// 侦听器也可以侦听props的数据

//导入鼠标位置控制插件
import { useMouseInElement } from '@vueuse/core'
const target = ref(null)
//isOutside 鼠标是否在目标target外面:
const {  isOutside } = useMouseInElement(target)


watch( isOutside,() => {
    //如果鼠标移入到盒子里面 ,关闭自动轮播
  
    //鼠标 不在盒子内 可以开启自动轮播
    // 轮播图长度大于1并且标志位是放开的
    if (lang.value > 1 && props.autoplay && isOutside.value) {
      autoplayFn();
    }else{
      clearInterval(timer.value);
    }
  },
  { immediate: true }
);

// 组件销毁,清理定时器
onUnmounted(() => {
    clearInterval(timer)
})
</script>

<template>
  <div
    class="xtx-carousel"
    :style="{ height: height + 'px', width: width + 'px' }"
    ref="target"
  >
    <ul class="carousel-body">
      <!-- 图片 -->
      <li
        class="carousel-item"
        v-for="(item, i) in list"
        :key="i"
        :class="{ fade: index === i }"
      >
        <!--  <RouterLink to="/"> -->
        <img :src="item.imgUrl" alt="" />
        <!--  </RouterLink> -->
      </li>
    </ul>
    <!-- 左右箭头 -->
    <a href="javascript:;" class="carousel-btn prev" @click="prev"
      ><el-icon><ArrowLeftBold /></el-icon
    ></a>
    <a href="javascript:;" class="carousel-btn next" @click="next"
      ><el-icon><ArrowRightBold /></el-icon
    ></a>
    <!-- 指示小圆点 -->
    <div class="carousel-indicator">
      <span
        v-for="(item, i) in list"
        :key="i"
        :class="{ active: index === i }"
        @click="clickindex(i)"
      ></span>
    </div>
  </div>
</template>

<style scoped lang="scss">
.xtx-carousel {
  position: relative;
  .carousel {
    &-body {
      width: 100%;
      height: 100%;
    }
    &-item {
      width: 100%;
      height: 100%;
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      transition: opacity 0.5s linear;
      &.fade {
        opacity: 1;
        z-index: 1;
      }
      img {
        width: 100%;
        height: 100%;
      }
    }
    &-indicator {
      position: absolute;
      left: 0;
      bottom: 20px;
      z-index: 2;
      width: 100%;
      text-align: center;
      span {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: rgba(0, 0, 0, 0.2);
        border-radius: 50%;
        cursor: pointer;
        ~ span {
          margin-left: 12px;
        }
        &.active {
          background: #fff;
        }
      }
    }
    &-btn {
      width: 44px;
      height: 44px;
      background: rgba(0, 0, 0, 0.2);
      color: #fff;
      border-radius: 50%;
      position: absolute;
      top: 45%;
      z-index: 2;
      text-align: center;
      line-height: 44px;
      opacity: 0;
      transition: all 0.5s;
      &.prev {
        left: 20px;
      }
      &.next {
        right: 20px;
      }
    }
  }
  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }
}
</style>

index2.vue

<script setup>
import { ref, computed, watch,onUnmounted } from "vue";

const props = defineProps({
  width: Number,
  height: Number,
  list: Array,
  autoplay:Boolean,
  duration:Number
});
//过度时间:
const ition=ref(1);
//左边的距离
const leftVal=ref(0);
//当前图片索引:
const index = ref(0);
//左边按钮
const prev = () => {
  

  if(index.value==0){
    index.value = lang.value - 1;
    ition.value=0// 将过渡时间变成0,瞬间位移到最后一张图
    leftVal.value=lang.value*props.width// 瞬间移动
    
    setTimeout(()=>{  // 通过延时障眼法,归原过渡时间,执行真正的“上一张”函数
      ition.value=0.8
      leftVal.value -= props.width
    },ition.value*1000)
  }else{
    index.value--;
    ition.value=0.8
    leftVal.value -= props.width
  }

};
//右边按钮:
const next = () => {
 
 
  if(index.value==lang.value-1){
    index.value = 0;
    ition.value=0.8
    leftVal.value+=props.width
    
           setTimeout(()=>{
            ition.value=0
             leftVal.value=0
           },ition.value*1000)

  }else{
    index.value++;
    ition.value=0.8
    leftVal.value+=props.width
  }
};
// 计算图片列表的长度
const lang = computed(() => {
  return props.list.length;
});
//点击指示器:
const clickindex = (i) => {
  index.value = i;
};

// 封装一个自动轮播的函数
const timer = ref(null);
const autoplayFn = () => {
  // 防止触发多个定时任务
  clearInterval(timer.value);
  timer.value = setInterval(() => {
    if(index.value==lang.value-1){
    index.value = 0;
    ition.value=0.8
    leftVal.value+=props.width
    
           setTimeout(()=>{
            ition.value=0
             leftVal.value=0
           },ition.value*1000)

  }else{
    index.value++;
    ition.value=0.8
    leftVal.value+=props.width
  }
  }, props.duration * 1000);
};
// 侦听器也可以侦听props的数据

//导入鼠标位置控制插件
import { useMouseInElement } from '@vueuse/core'
const target = ref(null)
//isOutside 鼠标是否在目标target外面:
const {  isOutside } = useMouseInElement(target)


watch( isOutside,() => {
    //如果鼠标移入到盒子里面 ,关闭自动轮播
  
    //鼠标 不在盒子内 可以开启自动轮播
    // 轮播图长度大于1并且标志位是放开的
    if (lang.value > 1 && props.autoplay && isOutside.value) {
      autoplayFn();
    }else{
      clearInterval(timer.value);
    }
  },
  { immediate: true }
);




// 组件销毁,清理定时器
onUnmounted(() => {
    clearInterval(timer)
})
</script>

<template>
  <div
    class="xtx-carousel"
    :style="{ height: height + 'px', width: width + 'px' }"
    ref="target"
  >
    <ul class="carousel-body" :style="{width: width*(lang+1) +'px',left:`-${leftVal}px`,transition:`${ition}s`}"  >
      <!-- 图片 -->
      <li
        class="carousel-item"
        v-for="(item, i) in list"
        :key="i"
        :style="{  width: width + 'px' }"
      >
        <!--  <RouterLink to="/"> -->
        <img :src="item.imgUrl" alt="" />
        <!--  </RouterLink> -->
      </li>
       <!-- 复制第一张放到最后,以实现无缝无线循环滚动效果 -->
       <li class="carousel-item" :style="{width: width +'px'}">
       <img :src="list[0].imgUrl" alt="">
      </li>
    </ul>
    <!-- 左右箭头 -->
    <a href="javascript:;" class="carousel-btn prev" @click="prev"
      ><el-icon><ArrowLeftBold /></el-icon
    ></a>
    <a href="javascript:;" class="carousel-btn next" @click="next"
      ><el-icon><ArrowRightBold /></el-icon
    ></a>
    <!-- 指示小圆点 -->
    <div class="carousel-indicator">
      <span
        v-for="(item, i) in list"
        :key="i"
        :class="{ active: index === i }"
        @click="clickindex(i)"
      ></span>
    </div>
  </div>
</template>

<style scoped lang="scss">
.xtx-carousel {
  position: relative;
   overflow: hidden; 
  .carousel {
    &-body {
      position: absolute;
      height: 100%;
    }
    &-item {
      float: left;
      height: 100%;
     
      img {
        width: 100%;
        height: 100%;
      }
    }
    &-indicator {
      position: absolute;
      left: 0;
      bottom: 20px;
      z-index: 2;
      width: 100%;
      text-align: center;
      span {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: rgba(0, 0, 0, 0.2);
        border-radius: 50%;
        cursor: pointer;
        ~ span {
          margin-left: 12px;
        }
        &.active {
          background: #fff;
        }
      }
    }
    &-btn {
      width: 44px;
      height: 44px;
      background: rgba(0, 0, 0, 0.2);
      color: #fff;
      border-radius: 50%;
      position: absolute;
      top: 45%;
      z-index: 2;
      text-align: center;
      line-height: 44px;
      opacity: 0;
      transition: all 0.5s;
      &.prev {
        left: 20px;
      }
      &.next {
        right: 20px;
      }
    }
  }
  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }
}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用 Vue 的组件化思想来封装一个轮。首先,需要创建一个 Carousel 组件,然后在该组件中使用 Vue 的生命周期函数来实现轮的自动放和手动切换。具体实现可以参考以下代码: <template> <div class="carousel"> <div class="carousel-inner"> <div v-for="(item, index) in items" :key="index" :class="{ active: index === currentIndex }"> <img :src="item.src" alt=""> </div> </div> <a class="carousel-control-prev" href="#" role="button" @click="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="sr-only">Previous</span> </a> <a class="carousel-control-next" href="#" role="button" @click="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="sr-only">Next</span> </a> </div> </template> <script> export default { name: 'Carousel', props: { items: { type: Array, required: true } }, data() { return { currentIndex: 0, timer: null } }, mounted() { this.start() }, methods: { start() { this.timer = setInterval(() => { this.next() }, 3000) }, stop() { clearInterval(this.timer) this.timer = null }, prev() { this.currentIndex-- if (this.currentIndex < 0) { this.currentIndex = this.items.length - 1 } }, next() { this.currentIndex++ if (this.currentIndex >= this.items.length) { this.currentIndex = 0 } } }, watch: { currentIndex() { this.stop() this.start() } } } </script> <style> .carousel { position: relative; width: 100%; height: 300px; overflow: hidden; } .carousel-inner { position: absolute; width: 100%; height: 100%; display: flex; transition: transform 0.5s ease-in-out; } .carousel-inner > div { flex: 1; display: flex; justify-content: center; align-items: center; } .carousel-inner > div > img { max-width: 100%; max-height: 100%; } .carousel-inner > .active { transform: translateX(0); } .carousel-inner > .prev { transform: translateX(-100%); } .carousel-inner > .next { transform: translateX(100%); } .carousel-control-prev, .carousel-control-next { position: absolute; top: 50%; transform: translateY(-50%); z-index: 1; display: flex; justify-content: center; align-items: center; width: 50px; height: 50px; background-color: rgba(0, 0, 0, 0.5); border-radius: 50%; transition: background-color 0.2s ease-in-out; } .carousel-control-prev:hover, .carousel-control-next:hover { background-color: rgba(0, 0, 0, 0.8); } .carousel-control-prev-icon, .carousel-control-next-icon { display: inline-block; width: 20px; height: 20px; background-repeat: no-repeat; background-position: center; background-size: contain; fill: #fff; } .carousel-control-prev-icon { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M6.5 0l-3 3 3 3v-2h1v-2h-1v-2z'/%3E%3C/svg%3E"); } .carousel-control-next-icon { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l3 3-3 3v-2h-1v-2h1v-2z'/%3E%3C/svg%3E"); } </style> 在父组件中,可以通过以下方式来使用 Carousel 组件: <template> <div class="app"> <carousel :items="items"></carousel> </div> </template> <script> import Carousel from './Carousel.vue' export default { name: 'App', components: { Carousel }, data() { return { items: [ { src: 'https://picsum.photos/800/300?random=1' }, { src: 'https://picsum.photos/800/300?random=2' }, { src: 'https://picsum.photos/800/300?random=3' }, { src: 'https://picsum.photos/800/300?random=4' }, { src: 'https://picsum.photos/800/300?random=5' } ] } } } </script> <style> .app { max-width: 800px; margin: 0 auto; } </style> 这样就可以在页面上展示一个轮了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值