实现大转盘

116 阅读2分钟

实现一个大转盘 包含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; /* 鼠标悬停时显示为手型 */
}