admin管理员组

文章数量:1487745

用 UniApp 实现一个炫酷的做决定转盘

你是否也曾在朋友聚会上遇到选择困难症?今天吃什么、去哪玩,这些琐事总让人犯难。那如果我们有个决策转盘,是不是瞬间逼格满满?让转盘来决定一切,省心又有趣!本文就来带你实现这样一个小工具——一个炫酷的做决定转盘

开始吧!我们先来个简单的布局

转盘功能说难不难,接下来就让我们轻松一步步搞定!首先,给大家看一下主要的布局代码。转盘放在中间,点击按钮开始旋转,当然少不了一个漂亮的悬浮设置按钮啦。

代码语言:html复制
<template>
  <view class="container">
    <view class="wheel-container">
      <view class="wheel" :style="{ transform: 'rotate(' + rotationAngle + 'deg)', background: wheelGradient }">
        <view v-for="(option, index) in options" :key="index" class="wheel-text" :style="getTextStyle(index)">
          {{ option.name }}
        </view>
      </view>
      <view class="pointer"></view>
    </view>
    <button @click="spinWheel" class="spin-button">点击转动</button>
    <view class="floating-button" @click="toggleOptionEditor">⚙️</view>

    <!-- 弹出选项编辑器 -->
    <view v-if="showOptionEditor" class="option-editor">
      <!-- 表头 -->
      <view class="option-header">
        <text>选项名</text>
        <text>权重</text>
        <text>操作</text>
      </view>
      <!-- 选项列表 -->
      <view v-for="(option, index) in options" :key="index" class="option-item">
        <input v-model="option.name" placeholder="选项名称" />
        <input v-model.number="option.weight" type="number" placeholder="权重" />
        <button @click="removeOption(index)">删除</button>
      </view>
      <button @click="addOption">添加新选项</button>
      <view class="button-row">
        <button @click="saveOptions">确定</button>
        <button @click="toggleOptionEditor">返回</button>
      </view>
    </view>

    <!-- 背景遮罩 -->
    <view v-if="showOptionEditor" class="backdrop" @click="toggleOptionEditor"></view>
  </view>
</template>
转盘怎么转?——实现转动逻辑

核心逻辑来了!通过点击按钮,转盘转动起来,并且最后停在一个选项上,整个过程既要炫酷又要自然!为了让转盘转动带点神秘感,这里我们使用了一点缓动效果——让它一开始快速转动,逐渐减速,直到停止。

代码语言:javascript代码运行次数:0运行复制
methods: {
  spinWheel() {
    if (this.isSpinning) return; // 防止重复点击转动
    this.isSpinning = true;

    // 随机生成一个最终旋转的角度(确保转盘转了几圈后停下)
    const finalRotation = this.maxRotations * 360 + Math.random() * 360;

    const startTime = Date.now();

    const animate = () => {
      const elapsedTime = Date.now() - startTime;
      if (elapsedTime < this.spinDuration) {
        // 缓动效果
        const easeOutFactor = (elapsedTime / this.spinDuration) * (2 - elapsedTime / this.spinDuration);
        this.rotationAngle = this.currentRotation + finalRotation * easeOutFactor;
        requestAnimationFrame(animate); // 帧动画,动起来!
      } else {
        // 最终停在某个选项
        this.rotationAngle = this.currentRotation + finalRotation;
        this.currentRotation = this.rotationAngle % 360;
        this.isSpinning = false;
        this.determineWinner(this.currentRotation); // 计算中奖选项
      }
    };

    animate(); // 动画启动!
  },
}
转盘的颜色很重要!——生成渐变背景

转盘的每个区域颜色要足够醒目,给每个选项一个独特的颜色才能让它看起来有活力。为了简单起见,我们用了 conic-gradient 来生成一个漂亮的扇形渐变背景。

代码语言:javascript代码运行次数:0运行复制
generateWheelGradient() {
  const totalWeight = this.options.reduce((sum, option) => sum + option.weight, 0);
  let currentAngle = 0;
  const gradientColors = ['#FF5733', '#33FF57', '#3357FF', '#F5FF33', '#FF33A8', '#33FFF3']; // 颜色可以自由发挥
  const gradients = this.options.map((option, index) => {
    const startAngle = currentAngle;
    const endAngle = startAngle + (option.weight / totalWeight) * 360;
    currentAngle = endAngle;
    return `${gradientColors[index % gradientColors.length]} ${startAngle}deg ${endAngle}deg`;
  });
  this.wheelGradient = `conic-gradient(${gradients.join(', ')})`;
}
让文字居中显示在扇形中

转盘是旋转的,但选项文字得稳稳地在每个扇形区域的中心位置,并且保持水平展示。用 transform 做旋转和偏移,这就好像魔法一样让文字乖乖待在扇形中。

代码语言:javascript代码运行次数:0运行复制
getTextStyle(index) {
  const totalWeight = this.options.reduce((sum, option) => sum + option.weight, 0);
  const startAngle = this.options.slice(0, index).reduce((sum, option) => sum + (option.weight / totalWeight) * 360, 0);
  const optionAngle = (this.options[index].weight / totalWeight) * 360;
  const textAngle = startAngle + optionAngle / 2;

  return {
    transform: `rotate(${textAngle}deg) translate(0, -130px) rotate(${-textAngle}deg)`, // 文字位于扇形中心
    position: 'absolute',
    top: '50%',
    left: '50%',
    'text-align': 'center',
    'font-size': '12px',
    'font-weight': 'bold',
    'transform-origin': 'center center',
  };
}
选项和权重管理——让每个选项都不一样

每个人都有自己的偏好,有些选项想更容易抽中,有些则是小概率事件。通过一个简单的编辑器,我们可以调整每个选项的权重,让重要的选项更容易被选中。你可以轻松地添加或删除选项,随心所欲地修改。

代码语言:javascript代码运行次数:0运行复制
methods: {
  toggleOptionEditor() {
    this.showOptionEditor = !this.showOptionEditor;
  },
  saveOptions() {
    this.generateWheelGradient(); // 修改选项后重新生成转盘背景
    this.showOptionEditor = false;
  },
  addOption() {
    this.options.push({ name: `新选项`, weight: 1 });
  },
  removeOption(index) {
    if (this.options.length > 2) {
      this.options.splice(index, 1);
    } else {
      uni.showToast({ title: '至少要有两个选项', icon: 'none' });
    }
  }
}
整体样式美化

最后,给大家一个简单又好看的样式,转盘、按钮都要美美哒!通过调整 CSS 代码,让转盘不仅有趣而且好看!

代码语言:css复制
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
.wheel-container {
  position: relative;
  width: 300px;
  height: 300px;
}
.wheel {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  position: absolute;
  top: 0;
  left: 0;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3); /* 让转盘有点立体感 */
}
.pointer {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 40px;
  background-color: red;
  transform: translate(-50%, -80%);
  clip-path: polygon(50% 0, 0 100%, 100% 100%);
}
.spin-button {
  margin-top: 20px;
  padding: 10px 20px;
  background-color: #007aff;
  color: white;
  border-radius: 5px;
  box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}

转盘还是略丑/(ㄒoㄒ)/~~,后面还需要时间优化,大致原理就是这样,大家加油!

本文标签: 用 UniApp 实现一个炫酷的做决定转盘