Vue3實現九宮格抽獎的示例代碼

前言

對象說晚飯吃什麼太難選擇,問我能不能做一個九宮格抽獎來決定我們晚上吃什麼,emmm。

既然對象都開口瞭,不做也不行啊,最後給大傢看一個簡化版的(沒有美工樣式、編輯獎品這些)

前期構思

首先是佈局,這個比較簡單,用彈性佈局(flex)就足夠瞭,抽獎盒子固定寬高,獎品項為盒子的1/3,超過換行就行,轉動方向是這樣的:

抽獎方式主要分為兩種,一種是隨機抽取(完全隨機),還有一種是指定獎品抽取(瞞著女朋友加的功能🫢,為瞭以後能吃到自己喜歡的東西)

轉動速度的規則是:加速 -> 勻速 -> 減速。

代碼實現用瞭 vue3

具體實現

1、佈局

佈局采用彈性佈局,利用 vuev-for 動態生成九個 item ,select 樣式是用來控制轉動的時候當前選中的 item。

這裡循環的key值,我使用的索引值,主要是為瞭後面添加編輯獎品的時候,id不一定能保證按順序排列,所以用索引值比較直觀。

<template>
  <div class="box">
    <div v-for="(item, index) in raffleItem" :key="index" :class="{item: true, select: selectItem === index}">{{ item.name }}</div>
  </div>
  <button @click="startRaffle">開始抽獎</button>
</template>
<script>
import { defineComponent } from 'vue';

export default defineComponent({
  setup() {
    // 獎品
    const raffleItem = [
      {name: '法拉利', id: 1},
      {name: '蘭博基尼', id: 2},
      {name: '保時捷', id: 3},
      {name: '寶馬', id: 4},
      {name: '悍馬人', id: 5},
      {name: '紅旗', id: 6},
      {name: '特斯拉', id: 7},
      {name: '比亞迪', id: 8},
      {name: '奔馳', id: 9}
    ]
    // 選中的item
    const selectItem = ref(0)
    return {
      raffleItem,
      selectItem
    }
  },
});
</script>

<style>
.box {
  width: 300px;
  height: 300px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  align-items: center;  
}
.item {
  width: 95px;
  height: 95px;
}
.box, .item {
  box-sizing: border-box;
  border: 1px solid;
  border-radius: 5px;
}
.select {
  border-color: red;
  color: red;
  background: #579393;
}
</style>

2、指定獎品

為每一個 item 添加單機事件 appoint(index),傳入參數為當前的索引值。

做成點擊事件指定獎品主要是為瞭不讓對象發現

// 指定的獎品
const appointRaffle = ref(null)
// 指定獎品
const appoint = (index) => {
  appointRaffle.value = index
}

3、抽獎

抽獎的具體實現:

  • 利用定時器 setTimeout 控制轉動速度speed
  • 轉動速度(speed)的規則為,通過圈數跟中獎項計算出總的轉動次數,然後先加速再勻速最後減速
  • 利用樣式規則來控制選中的 item selectItem
  • 轉動的圈數量activeTurns 通過隨機數取 10~20
  • 中獎的規則:圈數跟需要轉動的總圈數相同並且轉到本輪中獎的位置則停止轉動表示中獎
  • 每次抽獎前需要初始化各種狀態值,如:選中的item(selectItem)、當前中獎(activeRaffle)…
  • 如果已經在抽獎,開始抽獎按鈕就會失效
// 指定的獎品
const appointRaffle = ref(null)
// 指定獎品
const appoint = (index) => {
  appointRaffle.value = index
}
// 當前中獎
const activeRaffle = ref(null)
// 選中的item
const selectItem = ref(0)
// 定時器
const timer = ref(null)
// 圈數
const turnsNumbers = ref(0)
// 轉多少圈中獎
const activeTurns = ref(0)
// 初始轉動速度
const speed = ref(100)
// 剩餘幾個中獎
const surplusNum = computed(() => {
  // 剩餘圈數 * 9 + 指定中獎的索引
  return (activeTurns.value - turnsNumbers.value) * 9 + appointRaffle.value - selectItem.value
})
// 初始化
const init = () => {
  selectItem.value = 1
  activeTurns.value = 0
  turnsNumbers.value = 0
  speed.value = 100
  activeRaffle.value = null
}
// 開始抽獎
const startRaffle = () => {
  // 如果已經存在定時器則表示已經在轉動,不理會
  if(timer.value) return
  // 初始化
  init()
  // 如果沒有指定獎品則隨機指定一個獎品
  if(!appointRaffle.value) {
    // 取隨機數0-8,數組的索引值
    appointRaffle.value = Math.round(Math.random() * 8)
  }
  // 取隨機數10~20圈,id > 4時少轉一圈
  const num = Math.round(Math.random()*10) + 10
  activeTurns.value = appointRaffle.value > 4 ? num - 1 : num
  // 抽獎
  handleRaffle()
}

轉動的方法實現

這裡需要註意的是,我們使用的是索引值,所以轉動一圈為0~8,而不是1~9

// 抽獎方法
const handleRaffle = () => {
  // 每轉完一圈
  if (selectItem.value === 8) {
    turnsNumbers.value ++
    selectItem.value = 0
  } else {
    selectItem.value ++
  }
  // 轉動速度規則
  speed.value = speedRole()
  // 如果圈數跟需要轉動的總圈數相同並且轉到本輪中獎的位置則停止轉動
  if (activeTurns.value === turnsNumbers.value && selectItem.value === appointRaffle.value) {
    // 中獎
    activeRaffle.value = raffleItem[appointRaffle.value].name 
    // 清除定時器
    clearTimeout(timer.value)
    timer.value = null
    // 清除指定中獎項
    appointRaffle.value = null
  } else {
    // 定時器
    timer.value = setTimeout(handleRaffle, speed.value)
  }
}

轉動規則的方法

轉動速度分為4個階段

  • 前面的 1/3 加速轉動
  • 中間的 1/3 是勻速轉動
  • 後面的 1/3 是減速轉動
  • 最後的 9 個速度降低到 300 轉動

經過計算,在圈數的分為內,最後的減速轉動,不能把速度減少到 300 之上,所以不會出現最後 9 個加速轉動的情況

// 轉動速度規則-先加速在勻速最後減速
const speedRole = () => {
  const total = activeTurns.value * 9 + appointRaffle.value
  // 剩餘最後9個中獎時的時候速度降低到300
  if(surplusNum.value <= 9) return 300
  // 前3/1加速轉動
  if(surplusNum.value >=  total * 2 / 3) return speed.value <= 50 ? 50 : speed.value - 2
  // 最後的3/1減速每次+1
  if(surplusNum.value <=  total / 3) return speed.value + 1
  // 剩餘的中間勻速
  return speed.value
}

最終效果

以上就是Vue3實現九宮格抽獎的示例代碼的詳細內容,更多關於Vue九宮格抽獎的資料請關註WalkonNet其它相關文章!

推薦閱讀: