微信小程序实现转盘抽奖,可以自定义编辑奖项列表
这个功能可以分几步实现:
1. 界面设计:
- 转盘区域: 使用 canvas 绘制转盘,可配置扇形数量、颜色、文字等。
- 按钮: "开始/停止" 按钮控制转盘转动。
- 编辑按钮: 点击弹出弹窗,编辑转盘项目。
- 中奖弹窗: 显示中奖结果。
2. 数据结构:
使用数组存储转盘项目数据,例如:
1 2 3 4 5 6 | const prizeList = [ { name: '一等奖' , color: '#FFD700' }, { name: '二等奖' , color: '#C0C0C0' }, { name: '三等奖' , color: '#CD7F32' }, // ... 其他奖项 ]; |
3. 功能实现:
- 绘制转盘:
- 根据 prizeList 数据计算每个扇形的角度。
- 使用 canvas API 绘制扇形、文字、边框等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 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
绘制当前奖项区域的扇形。最后把canvas转换为base64图片地址。 - 记录角度信息: 将
currentAngle
和endAngle
存储到prizeList
数组中,方便后续判断中奖区域。 - 更新
currentAngle
: 将currentAngle
更新为endAngle
,以便绘制下一个奖项区域。 - 记录角度信息: 在
drawPrizeWheel
方法中,我们为每个奖项对象添加了startAngle
和endAngle
属性,用来存储该奖项区域的起始和结束角度。 - 判断指针位置: 在
stopRotate
方法中,我们循环遍历prizeList
数组,并根据每个奖项的startAngle
和endAngle
判断指针是否落在该区域内。
- 注意处理了跨越 0 度的情况,如果
startAngle
大于endAngle
,则表示该区域跨越了 0 度,需要分别判断指针是否大于等于startAngle
或者小于endAngle
。
通过以上修改,奖项区域将从 0 度开始绘制,并且每个区域的角度信息会被正确记录在 prizeList
数组中,然后在 stopRotate
方法中准确判断指针落在哪个区域,从而确定中奖结果。
- 转盘转动:
- 使用
setInterval/setTimeout
或requestAnimationFrame
实现动画效果。 - 控制转速和停止位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <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 中对应的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 数据后,重新绘制转盘。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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(); // 重新绘制转盘 }, |
4. 代码示例:
index.wxml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | < 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=" color: rgb(189, 99, 197);">{{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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | 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-20if (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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | .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; /* */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
对象中添加以下方法:
1 2 3 4 5 6 7 8 9 10 11 12 | // ... 其他代码 ... 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
方法:
- 在开始旋转转盘之前调用: 这样每次点击 "开始" 按钮时,奖项的顺序都会被打乱,增加随机性。
1 2 3 4 | startRotate() { if ( this .data.isRotating) return ; this .shufflePrizeList(); // 打乱奖项顺序// ... 其他代码 ... }, |
- 在保存奖项列表之后调用: 这样每次编辑完奖项并保存后,奖项的顺序也会被打乱。
1 2 3 4 | savePrizeList() { // ... 保存奖项列表逻辑 ...<br>this.shufflePrizeList(); <br>// 打乱奖项顺序<br>this.closeModal(); this .drawPrizeWheel(); }, |
- 在其他合适的时机调用: 根据你的需求,你也可以在其他时机调用该方法,例如在页面加载完成后调用。
选择一个合适的时机调用 shufflePrizeList
方法,就可以实现打乱奖项顺序,提高抽奖的概率性了。
通过以上修改,现在转盘将不再旋转,而是通过旋转指针来指向最终中奖区域。
希望以上信息能够帮助你! 😊
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本