纯CSS+JS制作抽奖大转盘

发布于:2025-08-14 ⋅ 阅读:(8) ⋅ 点赞:(0)

在大转盘游戏中,使用百分比计算概率是一种直观且常用的方法。这种方法通过为每个奖项分配一定的百分比概率,确保所有奖项的概率总和为 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的数量)
	// 权重 获奖概率 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.实现效果图

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


网站公告

今日签到

点亮在社区的每一天
去签到