效果图

使用

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


GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐