使用gsap搞一个轮播数字倒计时组件

37 阅读1分钟

不得不说。gsap真好用啊

<template>
  <div class="CountDownNumber-container" v-if="visiableModel">
    <div class="number-container">
      <div v-for="(num, i) in count" :key="num" class="num">
        {{ count - i }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { gsap } from 'gsap'

defineOptions({
  name: 'CountDownNumberCom',
})

const props = defineProps({
  visiableModel: {
    type: Boolean,
    default: false,
  },
  count: {
    type: Number,
    default: 3,
  },
})
const Emits = defineEmits(['update:visiableModel'])

const countNumber = ref(props.count)
const currentSlide = ref(0)
const slideElement = ref()

watch(
  () => props.visiableModel,
  (val) => {
    if (val) {
      nextTick(() => {
        slideElement.value = gsap.utils.toArray('.num')
        gsap.set(slideElement.value, { y: '100%', opacity: 0 })
        gsap.set(slideElement.value[0], { y: '0%', opacity: 1 })
        countDownFun()
      })
    }
  },
  { immediate: true },
)

function countDownFun() {
  const a = setInterval(() => {
    if (countNumber.value > 1) {
      // 倒计时到1后就隐藏
      countNumber.value--
      goToSlide(currentSlide.value + 1)
    } else {
      Emits('update:visiableModel', false)
      clearInterval(a)
    }
  }, 1000)
}

function goToSlide(index: number) {
  console.log(currentSlide.value, index)
  if (index === currentSlide.value) return
  if (index === props.count) return // 最后一个时不执行滑出动画
  // 当前滑出
  gsap.to(slideElement.value[currentSlide.value], {
    y: '100%',
    opacity: 0,
    duration: 0.8,
    ease: 'power2.inOut',
  })

  // 新滑入
  gsap.fromTo(
    slideElement.value[index],
    { y: '-100%', opacity: 0 },
    { y: '0%', opacity: 1, duration: 0.8, ease: 'power2.inOut' },
  )

  currentSlide.value = index
}
</script>

<style lang="scss" scoped>
.CountDownNumber-container {
  height: 100vh;
  width: 100vw;
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  .number-container {
    width: 1018px;
    height: 323px;
    background: linear-gradient(
      269deg,
      rgba(97, 160, 255, 0) 0%,
      rgba(131, 131, 131, 0.28) 11%,
      rgba(70, 70, 70, 0.56) 35%,
      rgba(27, 27, 27, 0.56) 61%,
      rgba(59, 59, 59, 0.28) 87%,
      rgba(97, 160, 255, 0) 100%
    );
    border-radius: 0px 0px 0px 0px;
    overflow: hidden;

    position: relative;
    .num {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;

      font-family: 'HYZhengYuan';
      font-weight: 800;
      font-size: 144px;
      color: #ff6363;
      text-stroke: 8px #ffffff;
      -webkit-text-stroke: 8px #ffffff;
      position: absolute;
      opacity: 0;
    }
  }
}
</style>

image.png

image.png