微信小程序实现转盘抽奖,可以自定义编辑奖项列表

这个功能可以分几步实现:

  1. 界面设计:

转盘区域: 使用 canvas 绘制转盘,可配置扇形数量、颜色、文字等。

按钮: "开始/停止" 按钮控制转盘转动。

编辑按钮: 点击弹出弹窗,编辑转盘项目。

中奖弹窗: 显示中奖结果。

  1. 数据结构:

使用数组存储转盘项目数据,例如:

javascript 复制代码
const prizeList = [
  { name: '一等奖', color: '#FFD700' },
  { name: '二等奖', color: '#C0C0C0' },
  { name: '三等奖', color: '#CD7F32' },
  // ... 其他奖项
];
  1. 功能实现:

绘制转盘:

根据 prizeList 数据计算每个扇形的角度。

使用 canvas API 绘制扇形、文字、边框等。

javascript 复制代码
drawPrizeWheel() {
    // 创建离屏 2D canvas 实例,创建canvas元素
    const canvas = wx.createOffscreenCanvas({type: '2d', width: 300, height: 300});
    // 获取 context。注意这里必须要与创建时的 type 一致const ctx = canvas.getContext('2d');
    const centerX = 150;
    const centerY = 150;
    const radius = 130;
    const prizeCount = this.data.prizeList.length;
    const anglePerItem = 360 / prizeCount;
    // 记录当前角度,初始为 0/90 度
    let currentAngle = 90; 
    for (let i = 0; i < prizeCount; i++) {
      ctx.beginPath();
      ctx.moveTo(centerX, centerY);
      ctx.arc(
        centerX,
        centerY,
        radius,
        (i * anglePerItem * Math.PI) / 180,
        ((i + 1) * anglePerItem * Math.PI) / 180,
      );
      ctx.closePath();
      ctx.fillStyle = this.data.prizeList[i].color;
      ctx.fill();
      // --- 绘制文字 ---
      ctx.save(); 
      // 保存当前画布状态
      ctx.font = '12px sans-serif';
      ctx.fillStyle = '#fff';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      const textAngle = (i * anglePerItem + anglePerItem / 2) * (Math.PI) / 180;
      const textX = centerX + radius * 0.7 * Math.cos(textAngle);
      const textY = centerY + radius * 0.7 * Math.sin(textAngle);
      ctx.fillText(this.data.prizeList[i].name, textX, textY);
      ctx.restore(); 
      // 恢复之前的画布状态// --- 文字绘制结束 ---
      // 计算当前奖项区域的结束角度
      let endAngle = currentAngle + anglePerItem;
      if(endAngle > 360){
        endAngle %= 360;
      }
      // 计算当前奖项区域的起始角度和结束角度
      // 将角度信息存储到 prizeList 数组中
      this.data.prizeList[i].startAngle = currentAngle;
      this.data.prizeList[i].endAngle = endAngle;
      // 更新 currentAngle,准备绘制下一个区域
      currentAngle = endAngle; 
    }
    // 将canvas转换为DataURL格式的图片var dataURL = canvas.toDataURL('image/png', 1);this.setData({wheelImg: dataURL});
  },

代码解释:

初始化 currentAngle: 在循环开始之前,将 currentAngle 初始化为 90,表示从 90 度开始绘制。因为canvas 绘制圆弧的起始角度是水平向右的 x 轴正方向,而不是竖直向上的 y 轴正方向。所以这里实际起始角度是从90度开始。

计算结束角度: 在每次循环中,根据 currentAngle 和 anglePerItem 计算当前奖项区域的结束角度 endAngle。

绘制扇形: 使用 currentAngle 和 endAngle 绘制当前奖项区域的扇形。将 currentAngle 和 endAngle 存储到 prizeList 数组中,方便后续判断中奖区域。更新 currentAngle: 将 currentAngle 更新为 endAngle,以便绘制下一个奖项区域。最后把canvas转换为base64图片地址。

记录角度信息: 在 drawPrizeWheel 方法中,我们为prizeList数组中每个奖项对象添加了 startAngle 和 endAngle 属性,用来存储该奖项区域的起始和结束角度。

判断指针位置: 在 stopRotate 方法中,我们循环遍历 prizeList 数组,并根据每个奖项的 startAngle 和 endAngle 判断指针是否落在该区域内。

注意处理了跨越 0 度的情况,如果 startAngle 大于 endAngle,则表示该区域跨越了 0 度,需要分别判断指针是否大于等于 startAngle 或者小于 endAngle。

通过以上修改,奖项区域将从 0 度开始绘制,并且每个区域的角度信息会被正确记录在 prizeList 数组中,然后在 stopRotate方法中准确判断指针落在哪个区域,从而确定中奖结果。

转盘转动:

使用 setInterval/setTimeout 或 requestAnimationFrame 实现动画效果。

控制转速和停止位置。

javascript 复制代码
<view class="pointer" style="transform: rotate({{pointerAngle}}deg)"></view>
//开始旋转
startRotate() {
    if (this.data.isRotating) return;
    this.setData({ isRotating: true });
    // 生成随机旋转圈数(至少旋转 6 圈)
    const randomRounds = 6 + Math.floor(Math.random() * 3); 
    // 生成随机停止角度
    const finalAngle = Math.floor(Math.random() * 360);
    // 计算总旋转角度
    const totalRotation = randomRounds * 360 + finalAngle;
    // 使用 setInterval 实现动画
    const startTime = Date.now();const frameRate = 80; 
    const rotateAnimation = () => {
      const currentTime = Date.now();
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / this.data.animationDuration, 1);
      // 使用 ease-out 动画曲线
      const easeOut = (t) => 1 - Math.pow(1 - t, 3);
      // 计算当前角度
      const currentAngle = easeOut(progress) * totalRotation;
      this.setData({ pointerAngle: currentAngle });
      if (progress < 1) {
        setTimeout(rotateAnimation, 1000 / frameRate); 
      } else {
        this.stopRotate();
      }
    };
    rotateAnimation();
},

代码解释:

随机旋转圈数: 在 startRotate 方法中,我们使用 randomRounds 变量来生成一个随机的旋转圈数,至少 3 圈,最多 6 圈。

随机停止角度: 使用 finalAngle 变量生成一个 0 到 360 之间的随机角度,表示指针最终停止的位置。

计算总旋转角度: 将旋转圈数转换为角度,再加上最终停止角度,得到总旋转角度 totalRotation。

使用 setInterval/setTimeout 实现动画: 使用 setInterval/setTimeout 按照帧率更新指针角度,并使用 easeOut 动画曲线使指针旋转更自然。

停止动画和判断中奖区域: 在 stopRotate 方法中,根据最终指针角度 finalAngle 计算中奖区域索引,并弹出中奖信息。

旋转指针: wxml 中使用 style="transform: rotate({{pointerAngle}}deg)" 控制指针旋转,pointerAngle 存储指针旋转角度。

指针旋转中心: wxss 中设置 .pointer 的 transform-origin: 50% 100%; 将旋转中心点设置为指针底部。

stopRotate 方法: 修改逻辑,计算指针需要旋转到的角度 targetAngle,并更新 pointerAngle 数据。

现在,转盘指针将会随机旋转几圈,然后随机停止在某个角度,并显示指针指向的奖项作为中奖结果。

中奖判断:

根据停止位置计算中奖索引。

显示中奖弹窗,展示 prizeList 中对应的数据。

javascript 复制代码
stopRotate() {
    let winningIndex = null;
    const prizeCount = this.data.prizeList.length;
    const anglePerItem = 360 / prizeCount;
    const finalAngle = this.data.pointerAngle;
    const pointerAngle = (finalAngle) % 360;
    // 循环遍历每个奖项区域,判断指针是否落在该区域内
    for (let i = 0; i < prizeCount; i++) {
      const { startAngle, endAngle } = this.data.prizeList[i];
      // 处理跨越 0 度的情况,跨越0度就是该区域的开始角度大于结束角度,如340-20
      if (startAngle > endAngle) {
        if (pointerAngle >= startAngle || pointerAngle < endAngle) {
          winningIndex = i;
          break;
        }
      } else {
        if (pointerAngle >= startAngle && pointerAngle < endAngle) {
          winningIndex = i;
          break;
        }
      }
    }
    this.setData({
      isRotating: false
    });
    const winningPrize = this.data.prizeList[winningIndex].name;
    wx.showModal({
      title: "恭喜!",
      content: `您获得了${winningPrize}!`,
      showCancel: false,
    });
},

代码解释:

获取旋转后的角度: finalAngle 表示指针旋转后的随机角度

计算中奖索引:将 finalAngle取余 360,得到相对于第一个奖项区域起始位置的角度pointerAngle 。

遍历奖项区域: 循环遍历每个奖项,计算每个奖项区域的起始角度 startAngle 和结束角度 endAngle。

判断指针位置: 判断 pointerAngle 是否落在当前奖项区域内 (startAngle 到 endAngle 之间)。

确定中奖索引: 如果指针落在某个奖项区域内,记录下该奖项的索引 winningIndex,并跳出循环。

处理结果: 根据 winningIndex 获取中奖信息,并进行后续处理。如果 winningIndex 为 null,则表示出现异常,需要进行相应的处理。

注意:

(startAngle 到 endAngle 之间)存在跨越0度的情况,要进行判断

如果你的奖项区域绘制顺序或方向与示例不同,你需要相应地调整计算逻辑。

希望这个解决方案可以帮助你!

编辑转盘:

弹窗中使用列表展示 prizeList 数据,可以进行增删改操作。

修改 prizeList 数据后,重新绘制转盘。

javascript 复制代码
editPrize() {
    this.setData({
      showModal: true
    });
  },
  closeModal() {
    this.setData({
      showModal: false
    });
  },
  addNewPrize() {
    const colorsLength = this.data.colorsList.length;
    const random = Math.floor(Math.random() * colorsLength);
    this.setData({
      prizeList: [...this.data.prizeList, {
        name: '',
        color: this.data.colorsList[random] || '#000000'
      }],
    });
  },
  deletePrizeItem(e) {
    const index = e.currentTarget.dataset.index;
    let updatedPrizeList = [...this.data.prizeList];
    updatedPrizeList.splice(index, 1); // 从数组中移除对应奖项
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  updatePrizeName(e) {
    const index = e.currentTarget.dataset.index;
    const value = e.detail.value;
    let updatedPrizeList = this.data.prizeList;
    updatedPrizeList[index].name = value;
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  updatePrizeColor(e) {
    const index = e.currentTarget.dataset.index;
    const color = e.detail.value;
    let updatedPrizeList = this.data.prizeList;
    updatedPrizeList[index].color = color;
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  savePrizeList() {
    // 将 prizeList 转换为 JSON 字符串并存储
    // 这里可以根据你的需求修改存储方式
    const prizeListStr = JSON.stringify(this.data.prizeList);
    // console.log("保存的 JSON 字符串:", prizeListStr);
    this.closeModal();
    this.drawPrizeWheel(); // 重新绘制转盘
  },
  1. 代码示例:

index.wxml

javascript 复制代码
<view class="container"><view class="wheel-container"> 
    <view class="prize-wheel"> 
      <image class="canvas" src="{{wheelImg}}"></image></view><view class="pointer" style="transform: rotate({{pointerAngle}}deg)"></view> 
  </view><button class="btn" bindtap="startRotate" disabled="{{isRotating}}">开始</button><button class="btn edit-btn" bindtap="editPrize">编辑</button>
  <modal title="编辑奖项" hidden="{{!showModal}}" bindcancel="closeModal">
    <view class="edit-area">
      <!-- <view class="color-picker-slider">
          <view>R: <slider min="0" max="255" value="{{r}}" bindchange="onColorSliderChange" data-channel="r"/></view>
          <view>G: <slider min="0" max="255" value="{{g}}" bindchange="onColorSliderChange" data-channel="g"/></view>
          <view>B: <slider min="0" max="255" value="{{b}}" bindchange="onColorSliderChange" data-channel="b"/></view>
          <view class="color-preview" style="background-color: rgb({{r}}, {{g}}, {{b}});"></view>
      </view> -->
      <view class="prize-item" wx:for="{{prizeList}}" wx:key="index"><input 
          class="prize-name" 
          placeholder="奖项名称" 
          value="{{item.name}}" 
          data-index="{{index}}"bindinput="updatePrizeName"
        /><input 
          class="color-picker" 
          type="color" 
          value="{{item.color}}" 
          data-index="{{index}}"bindchange="updatePrizeColor"
        />
        <button class="delete-btn" data-index="{{index}}" bindtap="deletePrizeItem">-</button>
      </view>
    </view>
        <button class="btn add-btn" bindtap="addNewPrize">+</button><button class="btn save-btn" bindtap="savePrizeList">保存</button>
  </modal>
</view>

index.js

javascript 复制代码
Page({
  data: {
    prizeList: [{
        name: '一等奖',
        color: '#FFD700'
      },
      {
        name: '谢谢参与',
        color: '#C0C0C0'
      },
      {
        name: '二等奖',
        color: '#CD7F32'
      },
      {
        name: '谢谢参与',
        color: '#C0C0C0'
      },
      {
        name: '三等奖',
        color: '#A0522D'
      },
      {
        name: '谢谢参与',
        color: '#C0C0C0'
      },
    ],
    prizeListStr: '',
    showModal: false,
    rotateAngle: 0, // 用于模拟转盘动画,实际并未使用
    animation: null, // 未使用
    pointerAngle: 0, // 指针角度
    isRotating: false, // 是否正在旋转
    animationDuration: 5000, // 动画持续时间 (毫秒)
    showColorPickerVisible: false,
    currentPrizeIndex: null,
    r: 0,
    g: 0,
    b: 0,
    colorsList: [
      '#FFD700', '#C0C0C0', '#CD7F32', '#A0522D', '#DC143C', '#FF69B4',
      '#BA55D3', '#7B68EE', '#6A5ACD', '#483D8B', '#4682B4', '#00CED1',
      '#5F9EA0', '#2E8B57', '#9ACD32', '#FFFF00', '#FFA500', '#FF4500',
      '#8B4513', '#D2691E', '#B8860B', '#808000', '#556B2F', '#228B22',
      '#008000', '#006400', '#90EE90', '#00FF7F', '#00FA9A', '#20B2AA',
      '#235788', '#697656', '#D935E9', '#B69754', '#BFA476', '#BAC289',
      '#983471', '#EA4586', '#EABCDE', '#ACBEAD', '#825673', '#65C946',
    ],
  },
  onLoad() {
    this.drawPrizeWheel();
  },
  onReady() {
  },
  onColorSliderChange(e) {
    const channel = e.currentTarget.dataset.channel;
    const value = e.detail.value;
    this.setData({
      [channel]: value
    });
  },
  drawPrizeWheel() {
    // 创建离屏 2D canvas 实例,创建canvas元素
    const canvas = wx.createOffscreenCanvas({type: '2d', width: 300, height: 300});
    // 获取 context。注意这里必须要与创建时的 type 一致
    const ctx = canvas.getContext('2d');
    const centerX = 150;
    const centerY = 150;
    const radius = 130;
    const prizeCount = this.data.prizeList.length;
    const anglePerItem = 360 / prizeCount;
  
    // 记录当前角度,初始为 0/90 度
    let currentAngle = 90; 
    for (let i = 0; i < prizeCount; i++) {
      ctx.beginPath();
      ctx.moveTo(centerX, centerY);
      ctx.arc(
        centerX,
        centerY,
        radius,
        (i * anglePerItem * Math.PI) / 180,
        ((i + 1) * anglePerItem * Math.PI) / 180,
      );
      ctx.closePath();
      ctx.fillStyle = this.data.prizeList[i].color;
      ctx.fill();
      // --- 绘制文字 ---
      ctx.save(); // 保存当前画布状态
      ctx.font = '12px sans-serif';
      ctx.fillStyle = '#fff';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      const textAngle = (i * anglePerItem + anglePerItem / 2) * (Math.PI) / 180;
      const textX = centerX + radius * 0.7 * Math.cos(textAngle);
      const textY = centerY + radius * 0.7 * Math.sin(textAngle);
      ctx.fillText(this.data.prizeList[i].name, textX, textY);
      ctx.restore(); // 恢复之前的画布状态
      // --- 文字绘制结束 ---
      // 计算当前奖项区域的结束角度
      let endAngle = currentAngle + anglePerItem;
      if(endAngle > 360){
        endAngle %= 360;
      }
      // 计算当前奖项区域的起始角度和结束角度
      // 将角度信息存储到 prizeList 数组中
      this.data.prizeList[i].startAngle = currentAngle;
      this.data.prizeList[i].endAngle = endAngle;
      // 更新 currentAngle,准备绘制下一个区域
      currentAngle = endAngle; 
    }
    // 将canvas转换为DataURL格式的图片
    var dataURL = canvas.toDataURL('image/png', 1);
    this.setData({wheelImg: dataURL});
  },
  startRotate() {
    if (this.data.isRotating) return;
    this.setData({ isRotating: true });
    // 生成随机旋转圈数(至少旋转 6 圈)
    const randomRounds = 6 + Math.floor(Math.random() * 3); 
    // 生成随机停止角度
    const finalAngle = Math.floor(Math.random() * 360);
    // 计算总旋转角度
    const totalRotation = randomRounds * 360 + finalAngle;
    // 使用 setInterval 实现动画
    const startTime = Date.now();
    const frameRate = 80;
    const rotateAnimation = () => {
      const currentTime = Date.now();
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / this.data.animationDuration, 1);
      // 使用 ease-out 动画曲线
      const easeOut = (t) => 1 - Math.pow(1 - t, 3);
      // 计算当前角度
      const currentAngle = easeOut(progress) * totalRotation;
      this.setData({ pointerAngle: currentAngle });
      if (progress < 1) {
        setTimeout(rotateAnimation, 1000 / frameRate); 
      } else {
        this.stopRotate();
      }
    };
    rotateAnimation();
  },
  stopRotate() {
    let winningIndex = null;
    const prizeCount = this.data.prizeList.length;
    const anglePerItem = 360 / prizeCount;
    const finalAngle = this.data.pointerAngle;
    const pointerAngle = (finalAngle) % 360;
    // 循环遍历每个奖项区域,判断指针是否落在该区域内
    for (let i = 0; i < prizeCount; i++) {
      const { startAngle, endAngle } = this.data.prizeList[i];
      // 处理跨越 0 度的情况,跨越0度就是该区域的开始角度大于结束角度,如340-20
      if (startAngle > endAngle) {
        if (pointerAngle >= startAngle || pointerAngle < endAngle) {
          winningIndex = i;
          break;
        }
      } else {
        if (pointerAngle >= startAngle && pointerAngle < endAngle) {
          winningIndex = i;
          break;
        }
      }
    }
    this.setData({
      isRotating: false
    });
    const winningPrize = this.data.prizeList[winningIndex].name;
    wx.showModal({
      title: "恭喜!",
      content: `您获得了${winningPrize}!`,
      showCancel: false,
    });
  },
  editPrize() {
    this.setData({
      showModal: true
    });
  },
  closeModal() {
    this.setData({
      showModal: false
    });
  },
  addNewPrize() {
    const colorsLength = this.data.colorsList.length;
    const random = Math.floor(Math.random() * colorsLength);
    this.setData({
      prizeList: [...this.data.prizeList, {
        name: '',
        color: this.data.colorsList[random] || '#000000'
      }],
    });
  },
  deletePrizeItem(e) {
    const index = e.currentTarget.dataset.index;
    let updatedPrizeList = [...this.data.prizeList];
    updatedPrizeList.splice(index, 1); // 从数组中移除对应奖项
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  updatePrizeName(e) {
    const index = e.currentTarget.dataset.index;
    const value = e.detail.value;
    let updatedPrizeList = this.data.prizeList;
    updatedPrizeList[index].name = value;
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  shufflePrizeList() {
    let updatedPrizeList = [...this.data.prizeList];
    for (let i = updatedPrizeList.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [updatedPrizeList[i], updatedPrizeList[j]] = [updatedPrizeList[j], updatedPrizeList[i]];
    }
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  updatePrizeColor(e) {
    const index = e.currentTarget.dataset.index;
    const color = e.detail.value;
    let updatedPrizeList = this.data.prizeList;
    updatedPrizeList[index].color = color;
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
  savePrizeList() {
    // 将 prizeList 转换为 JSON 字符串并存储
    // 这里可以根据你的需求修改存储方式
    const prizeListStr = JSON.stringify(this.data.prizeList);
    // console.log("保存的 JSON 字符串:", prizeListStr);
    this.shufflePrizeList(); //打乱奖项的排序,实现随机性
    this.closeModal();
    this.drawPrizeWheel(); // 重新绘制转盘
  },
})

index.wxss

css 复制代码
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: auto;
  padding-bottom: 0;
  padding-bottom: constant(safe-area-inset-bottom); /*兼容 IOS<11.2*/
  padding-bottom: env(safe-area-inset-bottom); /*兼容 IOS>11.2*/
}
.wheel-container {
  margin-top: 50rpx;
  width: 300px;
  height: 300px;
  position: relative;
}
.prize-wheel {
  width: 100%;
  height: 100%;
}
.canvas {
  width: 100%;
  height: 100%;
}
.pointer {
  width: 0px;
  height: 0px;
  border-bottom: 50px solid #ff0000;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  /* background-color: red; */
  position: absolute;
  bottom: 50%;
  left: 50%;
  transform-origin: 50% 100%; /* 设置旋转中心点为指针底部 */
  z-index: 10;
  margin-left: -10px; /* 添加 margin-left */
  margin-top: -10px;
}
.pointer::before{
  content: "";
  width: 20px;
  height: 20px;
  border: 0;
  padding: 0;
  border-radius: 50%;
  background-color: #ff0000;
  position: absolute;
  bottom: -60px;
  left: -10px;
  z-index: 10;
}
.btn {
  margin: 10px;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  background-color: #007bff;
  color: #fff;
  font-size: 16px;
}
.edit-btn {
  background-color: #28a745;
}
.save-btn {
  background-color: #28a745;
  margin-top: 20px;
}
.add-btn {
  background-color: #1989fa;
  margin-top: 10px;
}
.color-preview {
  width: 50px;
  height: 20px;
  border: 1px solid #ccc;
}
.edit-area {
  padding: 10rpx;
  overflow: auto;
  height: auto;
  max-height: 620rpx;
}
.delete-btn {
  background-color: #dc3545;
  /* 红色背景 */
  color: #fff;
  /* 白色文字 */
  border: none;
  border-radius: 50%;
  /* 圆形按钮 */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 55rpx !important;
  height: 55rpx !important;
  padding: 0;
  line-height: 55rpx;
  text-align: center;
  font-size: 12px;
  margin-left: 5px;
}
.prize-item {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}
.prize-name,
.color-picker {
  flex: 1;
  padding: 5px;
  border: 1px solid #ccc;
  margin-right: 5px;
}

注意: 以上代码只是一个示例,你需要根据实际需求进行调整和完善,例如:

添加动画效果,例如转盘加速、减速。

处理用户交互,例如点击开始按钮后禁用按钮,防止重复点击。

优化代码结构,提高代码可读性和可维护性。

另外,我们可以添加一个方法来打乱 prizeList 数组的顺序,从而增加抽奖的随机性。

在 page 对象中添加以下方法:

javascript 复制代码
// ... 其他代码 ...
  shufflePrizeList() {
    let updatedPrizeList = [...this.data.prizeList];
    for (let i = updatedPrizeList.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [updatedPrizeList[i], updatedPrizeList[j]] = [updatedPrizeList[j], updatedPrizeList[i]];
    }
    this.setData({
      prizeList: updatedPrizeList,
    });
  },
// ... 其他代码 ...

方法说明:

shufflePrizeList 方法使用 Fisher-Yates shuffle 算法来随机打乱数组元素的顺序。该算法会遍历数组,并将当前元素与随机选取的另一个元素交换位置。

调用该方法:

你可以在以下几种情况下调用 shufflePrizeList 方法:

在开始旋转转盘之前调用: 这样每次点击 "开始" 按钮时,奖项的顺序都会被打乱,增加随机性。

javascript 复制代码
startRotate() {
  if (this.data.isRotating) return;
  this.shufflePrizeList(); // 打乱奖项顺序// ... 其他代码 ...
},

在保存奖项列表之后调用: 这样每次编辑完奖项并保存后,奖项的顺序也会被打乱。

javascript 复制代码
savePrizeList() {
  // ... 保存奖项列表逻辑 ...
  this.shufflePrizeList(); 
  // 打乱奖项顺序
  this.closeModal();
  this.drawPrizeWheel(); 
},

在其他合适的时机调用: 根据你的需求,你也可以在其他时机调用该方法,例如在页面加载完成后调用。

选择一个合适的时机调用 shufflePrizeList 方法,就可以实现打乱奖项顺序,提高抽奖的概率性了。

你也可以进行点修改,实现指针不懂,转盘转动。

希望以上信息能够帮助你! 😊

相关推荐
LJ小番茄2 小时前
Vue 常见的几种通信方式(总结)
前端·javascript·vue.js·html
pan_junbiao4 小时前
Vue组件:模板引用ref属性的使用
前端·javascript·vue.js
__lucas5 小时前
javascript-装饰器
开发语言·javascript·ecmascript
计算机源码社5 小时前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
春蕾夏荷_7282977255 小时前
electron nsis打包windows应用程序
javascript·windows·electron·nsis
想退休的搬砖人5 小时前
vue组件的生命周期
前端·javascript·vue.js
zhangjin12226 小时前
kettle从入门到精通 第八十五课 ETL之kettle kettle中javascript步骤调用外部javascript/js文件
javascript·数据仓库·etl·kettle调用外部js
CaptainDrake6 小时前
Vue:指令
前端·javascript·vue.js
软件技术NINI6 小时前
HTML——基本标签
前端·javascript·html
DreamByte6 小时前
Python Tkinter小程序
开发语言·python·小程序