unibest/src/pages/demo/page/lottery2.vue
2024-02-04 16:00:27 +08:00

182 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<route lang="json5">
{
layout: 'demo',
style: { navigationBarTitleText: '大转盘抽奖' },
}
</route>
<template>
<view class="mt-4 h-10 text-center">大转盘抽奖</view>
<div class="lottery-box">
<div class="lottery-list">
<div class="lottery-item" v-for="(n, index) in giftLen" :key="n">
<div class="lottery-item-inner">
<div class="lottery-item-gift">奖品{{ index + 1 }}</div>
</div>
</div>
<div
class="pointer"
@click="handleClick"
:style="{ transform: `rotate(${state.stopDeg}deg)` }"
>
<div>开始</div>
<div>抽奖</div>
</div>
</div>
</div>
<view class="leading-8">
<view class="mt-8 text-center text-green-600">下面是调试过程图片</view>
<view class="mb-8 text-center text-green-600">欢迎感兴趣的玩家继续优化</view>
<view class="text-center text-blue-600">计算lottery-item-inner节点的padding-left值</view>
<image
src="https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery/lottery2-1.png"
mode="widthFix"
class="w-full"
/>
<view class="text-center text-blue-600">调整lottery-item-gift节点</view>
<image
src="https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery/lottery2-2.png"
mode="widthFix"
class="w-full"
/>
</view>
</template>
<script lang="ts" setup>
const giftLen = 8
const deg = 360 / giftLen // 每份的角度
const loop = 4 // 转多少圈4圈
const state = reactive({
lottery: 0, // 本次抽奖的奖品索引
lastLottery: 0, // 上一次抽奖的奖品索引
stopDeg: 0, // 最终要旋转的角度
loading: false,
})
function handleClick() {
if (state.loading) return
state.loading = true
// 最终获得的奖品索引实际业务中是通过接口获取的这里使用随机数0~9来模拟下
state.lottery = Math.floor(Math.random() * giftLen)
console.log(state.lottery)
// 最终的旋转角度,指针指向本次奖品的旋转角度+指针从上一次的奖品指向回归0的旋转角度+ 默认转动三圈
state.stopDeg += (state.lottery + (giftLen - state.lastLottery)) * deg + loop * 360
// uni不支持addEventListener所以改用下面的
setTimeout(() => {
state.lastLottery = state.lottery
state.loading = false
// alert(`恭喜获得奖品${state.lottery + 1}`)
uni.showModal({
title: `恭喜获得奖品${state.lottery + 1}`,
})
}, 3000)
}
</script>
<style lang="scss">
.lottery-box {
display: flex;
align-items: center;
justify-content: center;
}
.lottery-list {
--size: 600rpx;
--half: calc(var(--size) / 2);
--len: 8; // 与代码 giftLen 长度一致
--deg: calc(360 / var(--len) * 1deg);
--deg-num: calc(360 / var(--len));
position: relative;
width: var(--size);
height: var(--size);
border: 2px solid #f55;
border-radius: 50%;
}
.lottery-item {
position: absolute;
top: 0;
left: var(--half);
width: var(--half);
height: var(--size);
overflow: hidden; // 把这个注释掉可以看到最初的模样
// background-color: #ff5350a1; // 放开这个可以看到最初的模样
transform-origin: left center;
}
.lottery-item-inner {
position: absolute;
top: 0;
left: calc(-1 * var(--half));
box-sizing: border-box;
width: var(--half);
height: var(--size);
padding-left: calc(((1 - sin(var(--deg-num))) * var(--size)));
font-size: 12px;
border-radius: var(--half) 0 0 var(--half);
transform: rotate(var(--deg));
transform-origin: right center;
}
.lottery-item-inner .lottery-item-gift {
display: block;
text-align: center;
transform: rotate(calc(-0.5 * var(--deg))) translateY(16px)
translateX(calc(0.5 * var(--half) * (1 - 1 / cos(0.5 * var(--deg)))));
transform-origin: center;
}
.lottery-item:nth-child(2n + 1) .lottery-item-inner {
background: #fef6e0a1;
}
.lottery-item:nth-child(2n) .lottery-item-inner {
background: #ffffffa1;
}
// TIPS: 与上面的--len一致
@for $i from 1 through 8 {
.lottery-item:nth-child(#{$i}) {
transform: rotate(calc(($i - 1 - 0.5) * var(--deg)));
}
}
.pointer {
--pointer-size: 40px;
--pointer-padding: calc(var(--pointer-size) / 5);
position: absolute;
top: calc(var(--half) - var(--pointer-size) / 2 - var(--pointer-padding));
left: calc(var(--half) - var(--pointer-size) / 2 - var(--pointer-padding));
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: var(--pointer-size);
height: var(--pointer-size);
padding: var(--pointer-padding);
font-size: 12px;
text-align: center;
background-color: #ffffffd1;
border: 1px solid #ff5350;
border-radius: 50%;
transition: transform 3s cubic-bezier(0.2, 0.93, 0.43, 1);
}
.pointer::after {
--caret-size: 8px;
position: absolute;
bottom: calc(var(--pointer-size) + var(--pointer-padding) * 2);
left: calc(var(--pointer-size) / 2 - var(-caret-size) / 2);
content: '';
border-color: transparent;
border-style: solid;
border-width: calc(var(--caret-size) * 2) var(--caret-size);
border-bottom-color: #ff5350;
transform-origin: center;
}
</style>