实现一个大转盘 包含vue版本和支付宝小程序版本
vue版本
<template>
<div>
<div
@click="spin"
class="wheel"
:style="{ transform: `rotate(${rotation}deg)` }"
>
<img src="https://img.ixintu.com/download/jpg/201912/be51e179e3e898c37196bad9fc3b7d16.jpg!con"
alt="转盘"
/>
</div>
</div>
</template>
<script setup lang="ts">
const rotation = ref(0)
const spin = () => {
const randomIndex = Math.floor(Math.random() * 8)
const targetRotation = 360 * 8 + randomIndex * 45 // 8圈 + 目标格子的角度
const duration = 2500 // 动画持续时间2秒
const startTime = performance.now()
const animate = (currentTime: number) => {
const elapsed = currentTime - startTime
const progress = Math.min(elapsed / duration, 1)
// const easing = easeInOutCubic(progress) // 使用缓动函数
const easing = easeOutSine(progress) // 使用缓动函数
rotation.value = targetRotation * easing
if (progress < 1) {
requestAnimationFrame(animate)
} else {
rotation.value = targetRotation // 确保最终停在目标位置
}
}
requestAnimationFrame(animate)
}
// 缓动函数
const easeInOutCubic = (t: number) => {
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2
}
// 新的缓动函数:easeOutSine
const easeOutSine = (t: number) => {
const res = Math.sin((t * Math.PI) / 2)
console.log(t, res)
return res // 使用正弦函数实现减速效果
}
// // 改造后的缓动函数:easeInOutCubic
// const easeInOutCubic = (t: number) => {
// if (t < 0.5) {
// return 4 * t * t * t // 前半段:加速
// } else {
// const adjustedT = t - 1 // 调整 t 值
// return 1 + 4 * adjustedT * adjustedT * adjustedT // 后半段:减速
// }
// }
</script>
<style scoped lang="scss">
.wheel {
width: 300px; // 根据需要调整大小
height: 300px;
overflow: hidden;
border-radius: 50%;
position: relative;
cursor: pointer;
}
</style>
支付宝版本
<view class="container">
<view class="wheel" bindtap="spin" style="transform: rotate({{rotation}}deg);">
<image src="https://img.ixintu.com/download/jpg/201912/be51e179e3e898c37196bad9fc3b7d16.jpg" alt="转盘" />
</view>
</view>
Page({
data: {
rotation: 0,
gridItems: ['格子1', '格子2', '格子3', '格子4', '格子5', '格子6', '格子7', '格子8']
},
spin() {
const randomIndex = Math.floor(Math.random() * this.data.gridItems.length);
const targetRotation = 360 * 5 + (randomIndex * 45); // 5圈 + 目标格子的角度
const duration = 2000; // 动画持续时间2秒
const startTime = Date.now();
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// 使用 easeOutSine 函数
let currentRotation = targetRotation * this.easeOutSine(progress);
// 在最后阶段,慢慢滚动到目标格子
if (progress >= 0.8) {
const slowDownProgress = (progress - 0.8) / 0.2; // 计算减速进度
currentRotation = targetRotation * this.easeInOutCubic(slowDownProgress); // 使用缓动函数
}
this.setData({ rotation: currentRotation });
if (progress < 1) {
requestAnimationFrame(animate);
} else {
this.setData({ rotation: targetRotation }); // 确保最终停在目标位置
}
};
requestAnimationFrame(animate);
},
// 新的缓动函数:easeOutSine
easeOutSine(t) {
return Math.sin((t * Math.PI) / 2); // 使用正弦函数实现减速效果
},
// 改造后的缓动函数:easeInOutCubic
easeInOutCubic(t) {
if (t < 0.5) {
return 4 * t * t * t; // 前半段:加速
} else {
const adjustedT = t - 1; // 调整 t 值
return 1 + 4 * adjustedT * adjustedT * adjustedT; // 后半段:减速
}
}
});
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.wheel {
width: 300px; /* 根据需要调整转盘大小 */
height: 300px;
overflow: hidden; /* 隐藏超出部分 */
border-radius: 50%; /* 圆形转盘 */
position: relative;
cursor: pointer; /* 鼠标悬停时显示为手型 */
}