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

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

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});
},

代码解释:

  1. 初始化 currentAngle: 在循环开始之前,将 currentAngle 初始化为 90,表示从 90 度开始绘制。因为canvas 绘制圆弧的起始角度是水平向右的 x 轴正方向,而不是竖直向上的 y 轴正方向。所以这里实际起始角度是从90度开始。
  2. 计算结束角度: 在每次循环中,根据 currentAngle 和 anglePerItem 计算当前奖项区域的结束角度 endAngle
  3. 绘制扇形: 使用 currentAngle 和 endAngle 绘制当前奖项区域的扇形。最后把canvas转换为base64图片地址。
  4. 记录角度信息: 将 currentAngle 和 endAngle 存储到 prizeList 数组中,方便后续判断中奖区域。
  5. 更新 currentAngle: 将 currentAngle 更新为 endAngle,以便绘制下一个奖项区域。
  6. 记录角度信息: 在 drawPrizeWheel 方法中,我们为每个奖项对象添加了 startAngle 和 endAngle 属性,用来存储该奖项区域的起始和结束角度。
  7. 判断指针位置: 在 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();
},

代码解释:

  1. 随机旋转圈数: 在 startRotate 方法中,我们使用 randomRounds 变量来生成一个随机的旋转圈数,至少 3 圈,最多 6 圈。
  2. 随机停止角度: 使用 finalAngle 变量生成一个 0 到 360 之间的随机角度,表示指针最终停止的位置。
  3. 计算总旋转角度: 将旋转圈数转换为角度,再加上最终停止角度,得到总旋转角度 totalRotation
  4. 使用 setInterval/setTimeout 实现动画: 使用 setInterval/setTimeout 按照帧率更新指针角度,并使用 easeOut 动画曲线使指针旋转更自然。
  5. 停止动画和判断中奖区域: 在 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,
});
},

代码解释:

  1. 获取旋转后的角度: finalAngle 表示指针旋转后的随机角度
  2. 计算中奖索引:将 finalAngle取余 360,得到相对于第一个奖项区域起始位置的角度pointerAngle 。
  3. 遍历奖项区域: 循环遍历每个奖项,计算每个奖项区域的起始角度 startAngle 和结束角度 endAngle
  4. 判断指针位置: 判断 pointerAngle 是否落在当前奖项区域内 (startAngle 到 endAngle 之间)。
  5. 确定中奖索引: 如果指针落在某个奖项区域内,记录下该奖项的索引 winningIndex,并跳出循环。
  6. 处理结果: 根据 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();
},
  1. 在其他合适的时机调用: 根据你的需求,你也可以在其他时机调用该方法,例如在页面加载完成后调用。

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

通过以上修改,现在转盘将不再旋转,而是通过旋转指针来指向最终中奖区域。

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

posted @   geekplus  阅读(452)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示