Canvas绘制转盘更可控:可逐帧计算落点、动态更新奖品、精准控制旋转角度与停靠位置;需设固定宽高,手动绘制扇形与居中文字,用requestAnimationFrame实现带缓动的真旋转。

用 canvas 绘制转盘比用 CSS 动画更可控
纯 CSS 实现的转盘在旋转角度、停靠位置、减速效果上很难精确控制,尤其要对接抽奖逻辑时容易错位。用 canvas 可以逐帧计算指针落点、支持动态更新奖品、方便绑定点击/触摸事件。
关键点:
-
canvas需设置固定宽高(如width="400"、height="400"),避免缩放导致坐标偏移 - 绘制扇形要用
ctx.beginPath()+ctx.arc()+ctx.lineTo()闭合路径,别直接用clip()剪裁 - 文字居中显示需手动算基线:
ctx.textBaseline = "middle"+ctx.textAlign = "center" - 奖品名称过长时,用
ctx.measureText().width动态缩放字体或截断,否则会溢出扇区
让转盘“真转起来”得靠 requestAnimationFrame + 角度缓动
直接设 transform: rotate(3600deg) 看似简单,但无法中途暂停、无法读取当前角度、无法按概率控制停靠位置。必须自己维护旋转状态。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 定义目标角度
targetAngle(比如 360 × 5 + 42,表示转5圈再停在第2个奖品) - 每帧用缓动公式更新当前角度:
currentAngle += (targetAngle - currentAngle) * 0.1 - 当
Math.abs(targetAngle - currentAngle) 时视为停止,触发回调函数 - 停止后用
Math.round(currentAngle / sectorAngle) % prizeList.length算出中奖索引
抽中结果不准靠视觉判断,得用角度映射到奖品数组索引
人眼觉得指针指向某块区域,但代码里只有最终角度值。如果扇区划分不均、起始角度偏移、或旋转结束有微小误差,就可能判错。
可靠做法:
- 所有扇区等分(如8个奖品 → 每份
45度),起始角度统一从-22.5度开始(让第一个扇区中心对准 0°) - 归一化最终角度:
const norm = ((currentAngle % 360) + 360) % 360,避免负数或超 360 - 用
Math.floor((norm + 22.5) / 45) % 8直接换算索引,比用if-else判断区间更稳 - 服务端必须校验:前端只传索引,后端查表确认该索引是否有效、是否已领、是否在活动期内
移动端点击没反应?多半是没处理 touchstart 和 preventDefault
在 iOS Safari 或安卓 Chrome 上,click 事件有约 300ms 延迟,且转盘区域常被识别为可滚动内容,导致点击失效。
必须做三件事:
- 给
canvas添加touchstart监听,并在回调里调用event.preventDefault() - CSS 加上
canvas { touch-action: none; },禁用浏览器默认手势 - 避免在
canvas外层套div并监听 click —— 移动端 touch 事件不会自动冒泡到非 target 元素 - 真机测试时关闭“缩放”功能:
<meta name="viewport" content="width=device-width, user-scalable=no">
转盘逻辑本身不复杂,难的是角度归一、索引映射、触控兼容这三处细节。少处理一个,上线后就会出现“明明指在一等奖却弹出谢谢参与”的情况。



















