vue3 图片左右无限滚动-轮播功能

效果图

使用

<carouselPlay :sliders="imgs" :autoplay='true' :duration="5"></carouselPlay>

代码部分

<template>
  <div class='xtx-carousel' @mouseenter="stop()" @mouseleave="start()">
    <ul class="carousel-body" ref="carousel">
      <!-- 重复部分-无限滚动必须 -->
      <li class="carousel-item" v-for="(item, i) in sliders" :key="i">
        <img :src="item" alt="">
      </li>
      <!-- 默认内容 -->
      <li class="carousel-item" v-for="(item, i) in sliders" :key="i">
        <img :src="item" alt="">
      </li>
      <!-- 重复部分-无限滚动必须 -->
      <li class="carousel-item" v-for="(item, i) in sliders" :key="i">
        <img :src="item" alt="">
      </li>
    </ul>
    <!-- 手动滚动-自行替换按钮 -->
    <a @click="scrollFun(-1)" href="javascript:;" class="carousel-btn prev"><el-icon>
        <ArrowLeft />
      </el-icon></a>
    <!-- 手动滚动-自行替换按钮 -->
    <a @click="scrollFun(1)" href="javascript:;" class="carousel-btn next"><el-icon>
        <ArrowRight />
      </el-icon></a>
    <!-- <div class="carousel-indicator">
      <span @click="index = i" v-for="(item, i) in sliders" :key="i" :class="{ active: index === i }"></span>
    </div> -->
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
  sliders: {
    type: Array,
    default: () => []
  },
  duration: {
    type: Number,
    default: 2
  },
  autoplay: {
    type: Boolean,
    default: false
  }
});
const carousel = ref()
//视口宽度
var width = 0
let timer = null;
//单个图片宽度
var itemWidth = 0;
// 偏移量
var left = 0;

const autoplayFn = () => {
  clearInterval(timer)
  timer = setInterval(() => {
    scrollFun()
  }, props.duration * 1000)
}
/**
 * 
 * @param {*} step  step == -1 向右滚否则向左
 */
const scrollFun = (step) => {
  if (!carousel.value) return
  if (step == -1) {
    left += itemWidth;
  } else {
    left -= itemWidth;
  }
  if (left <= -width * 2) {

    // 核心代码-消除滚动到第一张再向左滚动导致动画闪动问题
    // 思路先左滚动到第一张的前一张,关闭动画,无感滚动到最后一张,再次循环
    // 定时器时间==动画时间
    setTimeout(() => {
      left = -width
      carousel.value.style.transitionDuration = "0s"
      carousel.value.style.transform = `translateX(${left}px)`;
    }, 500)

  } else if (left >= -width) {
    setTimeout(() => {
      left = -width * 2
      carousel.value.style.transitionDuration = "0s"
      carousel.value.style.transform = `translateX(${left}px)`;
    }, 500)
  } else {
    carousel.value.style.transitionDuration = "0.5s"
  }
  carousel.value.style.transform = `translateX(${left}px)`;
}

onMounted(() => {
  //视口宽度
  width = carousel.value.getBoundingClientRect().width / 3;
  //滚动到中间
  left = -width;
  var item = getComputedStyle(document.querySelector(".carousel-item"))
  // 单个图片宽度
  itemWidth = parseFloat(item.width) + parseFloat(item.marginLeft) + parseFloat(item.marginRight);

  if (props.sliders.length > 1 && props.autoplay) {
    carousel.value.style.transform = `translateX(${left}px)`;
    //开始滚动
    autoplayFn()
  }
})

onUnmounted(() => {
  clearInterval(timer);
  timer = null;
});

// 鼠标进入轮播图区域轮播图停止轮播
const stop = () => {
  if (timer) clearInterval(timer)
}
// 鼠标离开轮播图区域轮播图开始轮播
const start = () => {
  autoplayFn()
}

</script>
<style scoped lang="scss">
.xtx-carousel {
  white-space: nowrap;
  overflow: hidden;
  width: 100%;
  align-self: flex-start;
  display: flex;
  position: relative;

  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }

  .carousel-body {
    white-space: nowrap;
    // overflow: hidden;
    padding: 0;
    transition: all 0.5s;
  }

  .carousel-item {
    width: 388px;
    height: 280px;
    display: inline-block;
    // filter: drop-shadow(0px 4px 28px rgba(0, 0, 0, 0.16));
    border-radius: 8px;
    overflow: hidden;
    margin: 0 12px;

    img {
      width: 100%;
      height: 100%;
    }
  }

  .carousel-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;
      }
    }
  }

  .carousel-btn {
    width: 44px;
    height: 44px;
    background: rgba(0, 0, 0, 0.2);
    color: #fff;
    border-radius: 50%;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    text-align: center;
    line-height: 44px;
    opacity: 0;
    transition: all 0.5s;

    &.prev {
      left: 20px;
    }

    &.next {
      right: 20px;
    }
  }

}
</style>


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js 3可以使用transition组件和v-for指令来实现左右照片无缝滚动轮播图。首先,你需要设置一个容器元素来包裹照片,并设置它的宽度为照片的宽度的n倍,其中n为照片的数量。然后,使用v-for指令在容器中循环渲染照片。接下来,使用transition组件和transform属性来实现左右滚动效果。最后,使用setInterval函数来实现自动切换照片的功能。 代码示例如下: ```html <template> <div class="carousel-container"> <transition-group name="carousel-slide" tag="div"> <div v-for="(photo, index) in photos" :key="index" class="carousel-slide-item"> <img :src="photo" alt="photo" /> </div> </transition-group> </div> </template> <script> export default { data() { return { photos: [ "photo1.jpg", "photo2.jpg", "photo3.jpg", // 添加更多照片 ], currentIndex: 0, intervalId: null, }; }, mounted() { this.startAutoSlide(); }, beforeUnmount() { this.stopAutoSlide(); }, methods: { startAutoSlide() { this.intervalId = setInterval(() => { this.slideRight(); }, 3000); }, stopAutoSlide() { clearInterval(this.intervalId); }, slideLeft() { this.currentIndex = (this.currentIndex - 1 + this.photos.length) % this.photos.length; }, slideRight() { this.currentIndex = (this.currentIndex + 1) % this.photos.length; }, }, }; </script> <style> .carousel-container { width: 100%; overflow: hidden; } .carousel-slide-item { float: left; width: 100%; } .carousel-slide-enter-active, .carousel-slide-leave-active { transition: transform 0.5s; } .carousel-slide-enter, .carousel-slide-leave-to { transform: translateX(100%); } </style> ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值