纯CSS+JS制作抽奖大转盘
在大转盘游戏中,使用百分比计算概率是一种直观且常用的方法。这种方法通过为每个奖项分配一定的百分比概率,确保所有奖项的概率总和为 100%,从而实现公平且可控制的抽奖逻辑。
1.HTML代码和样式
<template><!-- 大转盘抽奖 --><div class="bigPages"><div class="bigBox"><div class="out-box" ref="outBox"><div v-for="(item, index) in awardList" :style="{'--i': index,'--color': setColor(index)}"><text>{{item.name}}</text></div></div><div class="inset" @click="awardStart">抽奖</div></div></div>
</template>
<style lang="scss" scoped>@mixin felx-center {display: flex;justify-content: center;align-items: center;}@font-face {font-family: 'diyFont';src: url('../assets/禹卫书法行书简体.ttf');}.bigPages {@include felx-center();height: 100vh;width: 100vw;margin: auto;.bigBox {@include felx-center();position: relative;}.out-box {position: relative;height: 300px;width: 300px;border-radius: 50%;background-color: red;overflow: hidden;// transform: rotate(45deg);div {@include felx-center();position: absolute;height: 50%;width: 150px;overflow: hidden;background-color: var(--color);// transform: rotate(calc(var(--i) * 45deg));transform-origin: right bottom;-webkit-clip-path: polygon(0 0, 37% 0, 100% 100%, 0 60%);clip-path: polygon(0 0, 59% 0, 100% 100%, 0 59%);text {transform: rotate(-45deg) translateY(-20px);}}}.inset {@include felx-center();position: absolute;height: 60px;width: 60px;border-radius: 50%;background-color: #fff;box-shadow: 0 0 3px 2px #fee;font-size: 25px;font-family: 'diyFont';font-weight: bold;cursor: pointer;}.inset::before {content: '';position: absolute;// top: -78px;// right: 20px;// border: 40px solid #fff;// border-left-width: 10px;// border-right-width: 10px;// border-left-color: transparent;// border-right-color: transparent;// border-top-color: transparent;top: -38px;right: 20px;height: 40px;width: 20px;-webkit-clip-path: polygon(50% 0, 0 100%, 100% 100%);clip-path: polygon(50% 0, 0 100%, 100% 100%);background-color: #fff;}}
</style>
2.JS实现逻辑
<script setup>import {ref,onMounted} from "vue"const awardList = ref([{name: '1号奖品',precent: 5}, //5%{name: '2号奖品',precent: 5},{name: '3号奖品',precent: 10},{name: '4号奖品',precent: 10},{name: '5号奖品',precent: 15},{name: '6号奖品',precent: 15},{name: '7号奖品',precent: 15},{name: '未中奖',precent: 25},])const outBox = ref(null)const textAll = ref([]);const divAll = ref([]);const isFlag = ref(true); //防止重复点击抽奖按钮const timer = ref(null);const rotateDeg = ref(0); //计算旋转度数 360 / 总数量(awardList的数量)// 权重 获奖概率 2const weight = ref([5, 10, 20, 30, 45, 60, 75, 100])onMounted(() => {rotateDeg.value = (360 / awardList.value.length).toFixed(2)textAll.value = document.querySelectorAll('text')divAll.value = document.querySelectorAll('.out-box > div')outBox.value.style.transform = "rotate(" + rotateDeg.value + "deg)"for (let i = 0; i < awardList.value.length; i++) {divAll.value[i].style.transform = "rotate(" + i * rotateDeg.value + "deg)"}})const awardStart = () => {if (isFlag.value) {// 不考虑概率问题 ---1// let random = parseInt(Math.random() * 8)// getAward( rotateDeg.value - (rotateDeg.value * random), awardList.value[random].name)// 数组权重计算概率 ---2// let random = parseInt(Math.random() * 100);// let randomWeight = weight.value.concat(random);// let randomSort = randomWeight.sort((a,b) => {// return a - b;// })// let randomIndex = randomSort.indexOf(random);// // 向逆时针旋转// getAward( rotateDeg.value - (rotateDeg.value * randomIndex), awardList.value[randomIndex].name)// 用百分比计算中奖概率问题(随机数在概率值之间的个数)---3let percentTotal = awardList.value.reduce((sum, per) => sum + per.precent, 0);let random = parseInt(Math.random() * percentTotal);let sumPercent = 0; //概率累计值let percentIndex = 0;for (let i = 0; i < awardList.value.length; i++) {// 累加值为-- 5, 10, 20, 30, 45, 60, 75, 100sumPercent += awardList.value[i].precent;if (random < sumPercent) {percentIndex = i // 找到中奖奖项break}}// 向逆时针旋转getAward(rotateDeg.value - (rotateDeg.value * percentIndex), awardList.value[percentIndex].name)}}// 转到那个奖项const getAward = (dun, text) => {isFlag.value = false;console.log('dd', dun + '---' + text);let begin = 0;let basic = 360 * 5; //多少圈1800 / 360timer.value = setInterval(() => {if (begin >= (basic + dun)) {isFlag.value = true;clearInterval(timer.value)}outBox.value.style.transform = "rotate(" + begin + "deg)";// 缓慢停止的公式begin += Math.ceil((basic + dun - begin) * 0.1);// begin += 20}, 20)}const setColor = (index) => {let str = ''switch (index) {case 0:str = '#ff8d79';break;case 1:str = '#86ffa2';break;case 2:str = '#d0b4ff';break;case 3:str = '#66ebff';break;case 4:str = '#ffa6ce';break;case 5:str = '#e4feff';break;case 6:str = '#a097ff';break;case 7:str = '#eab5ff';break;case 8:str = '#ffa6ce';break;case 9:str = '#e4feff';break;case 10:str = '#a097ff';break;}return str}
</script>
3.实现效果图
注:该笔记主要用于自我研究学习,如有好的想法和改进之处请在评论区提出。