基于vue的九宫格抽奖(动画速度可控制)

24 篇文章 0 订阅

效果图:

 

直接上代码:

<template>
  <div class="flex p-5">
    <div class="lists">
      <div
        class="list"
        :class="{ 'start-btn': item.level === 0, disabled: item.level === 0 && isRunning, active: activeIndex === index }"
        @click="listClick(item.level)"
        :data-index="index"
        v-for="(item, index) in prises"
        :key="item.id"
      >
        <span class="name">
          <span v-if="item.level > 0">{{ `${item.level}等奖:` }}</span>
          <br />
          <span class="name flex items-center justify-center text-xs">{{ item.name }}</span>
          <br />
          <span class="value" v-if="![0, 8].includes(item.level)">{{ `价值:¥${item.value}` }}</span>
        </span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  components: {},
  data() {
    return {
      prises: [
        { name: '小牛电动车', level: 5, value: 2999 },
        { name: '2022 M2 MacBookPro 13寸', level: 1, value: 13999 },
        { name: '京东1000元购物卡', level: 6, value: 1000 },
        { name: 'iphone14 Pro Max', level: 2, value: 11999 },
        { name: '抽奖', level: 0 },
        { name: 'Ipad', level: 4, value: 4399 },
        { name: '京东500元购物卡', level: 7, value: 500 },
        { name: '谢谢惠顾', level: 8 },
        { name: 'HP 暗夜精灵7代', level: 3, value: 7999 }
      ],
      winningOrder: 1, // 中几等奖
      isRunning: false, // 是否正在抽奖
      startSpeed: 150, // 初始动画速度
      speed: '', // 动画实时速度
      interval: null, // 定时器实例
      maxAnimationTime: 4500, // 最大抽奖动画时长
      activeIndex: '', // 当前走到的index
      rorateArr: [0, 1, 2, 5, 8, 7, 6, 3], // 动画路径数组
      rotateIndex: 0, // 路径数组走到第一格
      startTime: '', // 开始时间
      endTime: '' // 结束时间
    }
  },
  computed: {
    // 动画运行时长
    rotateTime() {
      return this.endTime - this.startTime
    },
    speedIntervalValue() {
      return this.startSpeed / 10
    }
  },
  created() {
    this.getPrises()
  },
  methods: {
    getPrises() {
      this.prises.forEach((i) => {
        i.id = this.randomId()
      })
    },
    randomId() {
      return Math.random()
    },
    listClick(level) {
      if (level == 0) {
        this.start()
      }
    },
    // 抽奖
    start() {
      if (this.isRunning) {
        return
      }
      this.isRunning = true
      this.reset()
      const timeout = setTimeout(() => {
        this.intervalFn()
        clearTimeout(timeout)
      }, this.speed)
    },
    intervalFn() {
      clearInterval(this.interval)
      this.interval = null
      if (!this.isRunning) {
        return
      }
      // 变动画速度(逐渐加快)
      this.speed -= this.speedIntervalValue

      if (this.speed <= 50) {
        // 最快速度
        this.speed = 50
      }

      // 距离动画时间结束不到3秒时,动画逐渐减慢
      if (this.maxAnimationTime - this.rotateTime <= 2000) {
        this.speed += this.speedIntervalValue * 2 // 这里为什么加两倍,因为再次进入intervalFn方法,默认会减一倍,所以这里实际上是相当于加一倍
      }

      if (this.rotateTime > this.maxAnimationTime) {
        // 超过时长了
        if (this.winningOrder == this.prises[this.activeIndex].level) {
          // 动画跑到了中奖奖品那
          this.isRunning = false
          console.log(`抽奖结束,奖品${this.winningOrder}等奖,用时:${(this.rotateTime / 1000).toFixed(2)}秒`)

          return
        }
      }

      this.rotate()
      this.interval = setInterval(this.intervalFn, this.speed)
    },
    // 旋转高亮算法
    rotate() {
      if (this.rotateIndex === this.rorateArr.length) {
        this.rotateIndex = 0
      }
      this.activeIndex = this.rorateArr[this.rotateIndex]
      this.endTime = new Date().getTime()

      this.rotateIndex += 1
    },
    // 重置
    reset() {
      this.startTime = new Date().getTime()
      this.endTime = this.startTime
      this.speed = this.startSpeed
      this.rotateIndex = 0
    }
  }
}
</script>
<style lang="scss" scoped>
$primary-color: #2ca1f4;

.lists {
  width: 500px;
  height: 500px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  .list {
    position: relative;
    width: 150px;
    height: 150px;
    padding: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #eee;
    color: $primary-color;
    &.active {
      background: green;
      color: #fff;
    }
    &.start-btn {
      cursor: pointer;
      color: #fff;
      background: $primary-color;
      &.disabled {
        cursor: not-allowed;
        background: #999;
      }
    }
    .name {
      text-align: center;
    }
    .image {
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: -1;
    }
  }
}
</style>

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值