Skip to content

勋章无限轮播图

效果 🎊

Slide 1
Slide 2
Slide 3
Slide 4

代码 📝

vue
<script setup lang="ts">
import { ref, onMounted, watch, onBeforeUnmount, nextTick } from 'vue';

const {
  animationSpeed = 40,
  offsetX = '0px',
  animationName = 'scroll-inifinite-swiper'
} = defineProps<{
  animationSpeed?: number;
  offsetX?: string;
  animationName?: string;
}>();

const allDataWidth = ref(0);
const slideTrack = ref<HTMLElement | null>(null);
function initAnimation() {
  if (!slideTrack.value) {
    return
  }
  // 计算子元素的总宽度
  nextTick(() => {
    if (!slideTrack.value) {
      return
    }
    let childWidth = 0;
    for (const child of slideTrack?.value?.children || []) {
      childWidth += child.clientWidth;
    }
    allDataWidth.value = childWidth;
    // 设置动画样式
    if (slideTrack.value) {
      slideTrack.value.style.animation = `${animationName} ${animationSpeed}s linear infinite`;
      slideTrack.value.style.width = `${allDataWidth.value * 2}px`; // 设置总宽度为两倍子元素宽度
    }
    // 获取原始子元素并克隆一次
    const originalChildren = Array.from(slideTrack.value.children);
    slideTrack.value.innerHTML = ''; // 清空当前内容避免重复
    slideTrack.value.append(...originalChildren, ...originalChildren.map(child => child.cloneNode(true)));
  });
}

// 在组件挂载时初始化动画
onMounted(() => {
  initAnimation();
});

// 在组件卸载时清理
onBeforeUnmount(() => {
  if (slideTrack.value) {
    slideTrack.value.style.animation = 'none';
  }
});

</script>

<template>
  <div class="infinite-swiper-slider">
    <div class="infinite-swiper-slide-track" ref="slideTrack">
      <slot />
    </div>
  </div>
</template>

<style lang="scss">
@keyframes scroll-inifinite-swiper {
  0% {
    transform: translateX(v-bind(offsetX));
  }

  100% {
    transform: translateX(-50%);
  }
}

.infinite-swiper-slider {
  margin: auto;
  overflow: hidden;
  position: relative;
  width: 100%;
  height: fit-content;

  .infinite-swiper-slide-track {
    display: flex;
    flex-shrink: 0;
    will-change: transform;
    animation: scroll-inifinite-swiper 40s linear infinite;

    &:hover {
      animation-play-state: paused;
    }
  }
}
</style>

使用 📖

vue
<script setup lang="ts"> 
import InfiniteSwiperV2 from '../../.vitepress/compnents/Swiper/InfiniteSwiperV2.vue'
</script>
<div>
  <InfiniteSwiperV2>
    <div class="text-center py-4 w-200px bg-red">Slide 1</div>
    <div class="text-center py-4 w-120px bg-blue">Slide 2</div>
    <div class="text-center py-4 w-100px bg-green">Slide 3</div>
    <div class="text-center py-4 w-300px bg-yellow">Slide 4</div>
  </InfiniteSwiperV2>
</div>

采用 Apache-2.0 license 协议