Skip to content

抽奖转盘


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
点击开始

源代码

vue
<template>
  <div class="lottery-box">
    <ul class="prize-list">
      <li v-for="index in 8" :key="index" :class="{ focus: index === current }">
        {{ index }}
      </li>
    </ul>
    <div class="prize-btn" @click="onStart">点击开始</div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue';
const prizeIndexMap = [0, 1, 2, 3, 5, 8, 7, 6, 4];
const current = ref(1);
const params = reactive({
  startIndex: 1,
  prizeIndex: 5, // 顺时针第5个
  presetLoop: 2,
  acceleration: 30,
  minSpeed: 60,
});
const isRunning = ref(false);

const start = (callback) => {
  if (isRunning.value) return false;
  isRunning.value = true;
  let index = params.startIndex;
  const prizeIndex = params.prizeIndex;
  var speedType = 'up';
  var speed = params.minSpeed + params.acceleration * 8;
  var loop = params.presetLoop;
  var isEnd = false;
  var setSpeed = {
    up: function () {
      return (speed -= params.acceleration);
    },
    uniform: function () {
      return speed;
    },
    down: function () {
      return (speed += params.acceleration);
    },
  };
  var animation = function () {
    setTimeout(() => {
      if (index === 8) {
        index = 1;
      } else {
        index++;
      }
      current.value = prizeIndexMap[index];
      // 点击开始后进入加速运动
      if (speedType === 'up') {
        // 未达到最高速度
        if (speed > params.minSpeed) {
          setSpeed[speedType]();
        } else {
          // 达到最高速度后进入匀速
          speedType = 'uniform';
        }
      }
      // 进入匀速
      else if (speedType === 'uniform') {
        // 到达触发奖项时进行减速
        if (index === prizeIndex) {
          loop--;
          loop === 0 ? (speedType = 'down') : console.log(`剩余${loop}圈`);
        } else {
          setSpeed[speedType]();
        }
      }
      // 进入减速
      else if (speedType === 'down') {
        if (index !== prizeIndex) {
          setSpeed[speedType]();
        } else {
          // 到达触发奖项时停止
          isEnd = true;
          isRunning.value = false;
        }
      }
      isEnd ? callback() : animation();
    }, speed);
  };
  animation();
};

const onStart = () => {
  start(() => {
    console.log('恭喜!');
    params.startIndex = params.prizeIndex;
    params.prizeIndex = parseInt(Math.random() * 8);
  });
};
</script>

<style scoped>
.lottery-box {
  width: 300px;
  height: 300px;
  position: relative;
  padding: 10px;
  background-color: teal;
}

.prize-list {
  list-style: none;
  width: 100%;
  height: 100%;
  padding: 5px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  margin: 0;
  padding: 0;
}

.prize-list > li,
.prize-btn {
  width: 84px;
  height: 84px;
  flex: none;
  display: flex;
  border-radius: 5px;
  background-color: silver;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.prize-btn {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}
.prize-list > li:nth-child(5) {
  margin-left: 30%;
}
.prize-list > li + li {
  margin-top: 0;
}
.prize-list > li.focus {
  background-color: bisque;
}
</style>