纯CSS+JS制作抽奖大转盘

在大转盘游戏中,使用百分比计算概率是一种直观且常用的方法。这种方法通过为每个奖项分配一定的百分比概率,确保所有奖项的概率总和为 100%,从而实现公平且可控制的抽奖逻辑。

1.HTML代码和样式

javascript 复制代码
<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>
javascript 复制代码
<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实现逻辑

javascript 复制代码
<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的数量)
	// 权重 获奖概率 2
	const 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)

			// 用百分比计算中奖概率问题(随机数在概率值之间的个数)---3
			let 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, 100
				sumPercent += 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 / 360
		timer.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.实现效果图

注:该笔记主要用于自我研究学习,如有好的想法和改进之处请在评论区提出。

相关推荐
Larcher6 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐18 分钟前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭30 分钟前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信1 小时前
我们需要了解的Web Workers
前端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu1 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花1 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋2 小时前
场景模拟:基础路由配置
前端
六月的可乐2 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程