prompt:
任务:制作单文件离线家常菜抽奖转盘HTML工具,纯前端,无后端,PC/手机自适应。
【硬性约束】
- 所有代码写在同一个HTML文件,保存后双击浏览器直接打开,不拆分任何文件
- 使用Tailwind CSS CDN + Font Awesome图标库,不引入额外第三方JS库
- UI风格:简约清爽,转盘动画顺滑,移动端优先适配触摸操作
- 代码保留关键注释,不压缩代码,方便后续自行新增菜品、修改分类
【功能需求】
- 转盘设计:转盘上只绘制【菜品分类】,不要罗列大量菜名,避免界面拥挤难看。
预设分类:素菜、荤菜、下饭菜、汤品、面食。 - 抽奖逻辑:点击按钮启动转盘动画,转盘停止选中分类;再从该分类菜品池随机抽取一道家常菜。
- 结果展示:弹窗/卡片展示抽中的菜名 + 简短易懂的家常做法。
- 内置菜品库:每个分类预置若干家常菜,附带简要做法,方便后续自行扩充。
- 交互细节:转动过程有过渡动画,禁止重复点击触发多次转盘。
【禁止事项】
不要登录、不要云服务、不要广告、不要多余特效。
输出要求:只返回完整HTML源码,附带简短使用说明。


html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<meta name="theme-color" content="#f97316" />
<title>家常菜抽奖转盘 · 今天吃什么</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Font Awesome 图标 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<script>
tailwind.config = {
theme: {
extend: {
colors: { brand: { 50: '#fff7ed', 100: '#ffedd5', 500: '#f97316', 600: '#ea580c', 700: '#c2410c' } },
boxShadow: { card: '0 1px 2px rgba(15,23,42,.04), 0 10px 28px -14px rgba(15,23,42,.18)' }
}
}
}
</script>
<style>
html, body { -webkit-tap-highlight-color: transparent; }
body { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; }
/* 转盘尺寸:手机上按视口宽度自适应,PC 上最大 360px,保证不拥挤 */
.wheel { width: min(86vw, 360px); aspect-ratio: 1 / 1; }
/* 滚动条:转盘旋转由 JS 设置 transform,过渡曲线让停止更自然 */
.wheel-spin { will-change: transform; }
/* 指针轻微呼吸感(静态,不做花哨特效) */
.safe-bottom { padding-bottom: calc(1.25rem + env(safe-area-inset-bottom)); }
@keyframes pop { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
.animate-pop { animation: pop .28s ease-out both; }
@keyframes pulseRing { 0%,100% { transform: scale(1); opacity: .55; } 50% { transform: scale(1.04); opacity: .9; } }
.spin-ready { animation: pulseRing 1.8s ease-in-out infinite; }
</style>
</head>
<body class="min-h-screen bg-gradient-to-b from-brand-50 via-white to-slate-50 text-slate-800 antialiased">
<div class="max-w-md mx-auto px-4 pt-5 safe-bottom">
<!-- ===================== 标题 ===================== -->
<header class="text-center mb-4">
<div class="inline-flex items-center justify-center w-12 h-12 rounded-2xl bg-brand-500 text-white text-xl shadow-card mb-2.5">
<i class="fa-solid fa-utensils"></i>
</div>
<h1 class="text-lg font-semibold tracking-tight">今天吃什么?</h1>
<p class="text-xs text-slate-500 mt-1">转盘抽分类 · 再从分类里随机挑一道家常菜</p>
</header>
<!-- ===================== 转盘 ===================== -->
<section class="flex flex-col items-center">
<div class="relative">
<!-- 外圈装饰:白环 + 阴影,让转盘更立体 -->
<div class="wheel relative rounded-full p-2.5 bg-white shadow-card">
<!-- 指针:固定在正上方(12 点方向),不随转盘旋转 -->
<div class="absolute left-1/2 -translate-x-1/2 -top-1 z-20">
<div class="w-0 h-0 border-l-[9px] border-r-[9px] border-t-[18px] border-l-transparent border-r-transparent border-t-brand-600 drop-shadow"></div>
</div>
<!-- 转盘本体:背景由 JS 生成 conic-gradient(只画分类,不画菜名) -->
<div id="wheel" class="wheel-spin absolute inset-2.5 rounded-full overflow-hidden ring-1 ring-black/5"
style="transform: rotate(0deg);">
<!-- 分类文字标签由 JS 注入,按扇区中心角度定位,保持水平方便阅读 -->
</div>
<!-- 中心按钮:点击即开始抽奖(与主按钮同一入口,受防重复点击保护) -->
<button id="btnCenter" aria-label="开始抽奖"
class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10 w-[23%] aspect-square rounded-full bg-white shadow-lg grid place-items-center text-brand-600 active:scale-95 transition">
<i id="centerIcon" class="fa-solid fa-play text-lg"></i>
</button>
</div>
</div>
<!-- 主按钮 -->
<button id="btnSpin" class="mt-6 w-full max-w-[280px] inline-flex items-center justify-center gap-2 bg-brand-500 hover:bg-brand-600 active:scale-[.99] disabled:opacity-60 disabled:active:scale-100 text-white font-medium rounded-2xl px-6 py-3.5 shadow-card transition">
<i id="spinIcon" class="fa-solid fa-rotate"></i><span id="spinText">开始抽奖</span>
</button>
<!-- 分类概览:显示每个分类的菜品数量,点击可查看包含哪些菜(纯展示,不参与抽奖) -->
<div id="catChips" class="mt-4 flex flex-wrap justify-center gap-1.5"></div>
</section>
<!-- ===================== 结果卡片 ===================== -->
<section id="resultCard" class="hidden mt-5 bg-white rounded-3xl shadow-card p-4 sm:p-5 border border-slate-100">
<div class="flex items-start gap-3">
<div id="resIcon" class="w-11 h-11 shrink-0 rounded-2xl bg-brand-50 text-brand-600 grid place-items-center text-lg">
<i class="fa-solid fa-bowl-food"></i>
</div>
<div class="min-w-0 flex-1">
<div class="flex items-center gap-2 flex-wrap">
<span id="resDish" class="text-base font-semibold">---</span>
<span id="resCat" class="text-[11px] px-2 py-0.5 rounded-md bg-slate-100 text-slate-500">---</span>
</div>
<p class="text-[11px] text-slate-400 mt-1 flex items-center gap-1">
<i class="fa-solid fa-lightbulb"></i>家常做法
</p>
<p id="resHow" class="text-sm text-slate-600 mt-1.5 leading-relaxed">---</p>
</div>
</div>
<div class="mt-4 grid grid-cols-2 gap-2.5">
<button id="btnReroll" class="inline-flex items-center justify-center gap-1.5 rounded-xl border border-slate-200 px-3 py-2.5 text-sm text-slate-600 active:bg-slate-50 transition">
<i class="fa-solid fa-shuffle text-xs"></i>换一道
</button>
<button id="btnAgain" class="inline-flex items-center justify-center gap-1.5 rounded-xl bg-slate-900 text-white px-3 py-2.5 text-sm active:scale-[.99] transition">
<i class="fa-solid fa-rotate-right text-xs"></i>再转一次
</button>
</div>
</section>
<!-- ===================== 分类菜品速查(折叠) ===================== -->
<section class="mt-5">
<button id="btnToggleLib" class="w-full flex items-center justify-between bg-white rounded-2xl shadow-card px-4 py-3 text-sm text-slate-600 active:bg-slate-50 transition">
<span class="flex items-center gap-2"><i class="fa-solid fa-book-open text-brand-500"></i>菜品库速查</span>
<i id="libArrow" class="fa-solid fa-chevron-down text-xs text-slate-400 transition-transform"></i>
</button>
<div id="libBox" class="hidden mt-2.5 space-y-2.5"></div>
</section>
<footer class="text-center text-[11px] text-slate-400 mt-6">
<i class="fa-solid fa-circle-info mr-1"></i>纯前端离线运行,菜品数据写在文件顶部,可直接自行增删
</footer>
</div>
<script>
/* =========================================================================
* 家常菜抽奖转盘 ------ 单文件 / 纯前端 / 无后端
* 结构:① 菜品库(可自行增删)② 分类与配色 ③ 转盘绘制 ④ 抽奖逻辑 ⑤ 交互绑定
* ========================================================================= */
/* ------------------------------------------------------------------
* ① 菜品库:CATEGORIES 里定分类,DISHES 里放菜名 + 家常做法
* ➜ 想加菜:往对应分类的数组里加一条 { name: '菜名', how: '一句话做法' } 即可,
* 转盘与统计会自动适配(数量标签、概率都会跟着变)。
* ------------------------------------------------------------------ */
const DISHES = {
'素菜': [
{ name: '清炒时蔬', how: '青菜洗净切段,热油爆香蒜末,大火快炒 1 分钟,加盐出锅。' },
{ name: '蒜蓉西兰花', how: '西兰花掰小朵焯水 1 分钟;蒜末爆香,下西兰花翻炒,盐调味。' },
{ name: '手撕包菜', how: '包菜手撕成块,干辣椒蒜片爆锅,大火爆炒,沿锅边淋一点香醋。' },
{ name: '干煸豆角', how: '豆角切段小火慢煸至表皮起皱,加蒜末、生抽、少许肉末炒匀。' },
{ name: '醋溜白菜', how: '白菜帮斜切,热油爆香花椒,下白菜大火炒,出锅前烹香醋和少许糖。' },
{ name: '凉拌黄瓜', how: '黄瓜拍裂切段,加蒜末、生抽、香醋、香油拌匀,冷藏 10 分钟更爽口。' },
{ name: '蒜蓉菠菜', how: '菠菜焯水去涩过凉,挤干水分,蒜末热油一泼,加盐和生抽拌匀。' },
{ name: '家常豆腐', how: '北豆腐切块煎至两面金黄,加生抽、蚝油、少量水焖 2 分钟收汁。' },
{ name: '香菇青菜', how: '香菇切片先炒出香,下青菜同炒,加蚝油和少许水淀粉勾薄芡。' },
{ name: '番茄炒蛋', how: '鸡蛋炒至半凝盛出,番茄炒出汁回锅同炒,加少许糖提鲜、盐调味。' }
],
'荤菜': [
{ name: '红烧肉', how: '五花肉焯水切块,炒糖色上色,加生抽老抽、葱姜八角,小火炖 40 分钟收汁。' },
{ name: '糖醋排骨', how: '排骨焯水后煎香,按 1 料酒 2 酱油 3 醋 4 糖调汁,焖 20 分钟大火收汁。' },
{ name: '可乐鸡翅', how: '鸡翅两面煎金黄,倒可乐没过鸡翅,加姜片和生抽,中火焖 15 分钟收浓。' },
{ name: '宫保鸡丁', how: '鸡丁上浆滑炒,花生米炸香,用葱段、干辣椒、糖醋酱油调汁快炒裹匀。' },
{ name: '土豆炖牛肉', how: '牛肉焯水后与土豆块同炖 40 分钟,加生抽、八角,炖到牛肉软烂、土豆起沙。' },
{ name: '清蒸鲈鱼', how: '鲈鱼改刀铺姜丝,水开大火蒸 8 分钟,倒掉腥水,淋蒸鱼豉油再泼热油。' },
{ name: '回锅肉', how: '五花肉煮至断生切片,煸出油至卷曲,加豆瓣酱、青蒜苗、甜面酱炒香。' },
{ name: '葱爆羊肉', how: '羊肉片用蛋清淀粉抓匀,大火快炒变色盛出,爆香大葱回锅,淋料酒生抽。' },
{ name: '啤酒鸭', how: '鸭块焯水煸香,加一罐啤酒和生抽、姜蒜,焖 30 分钟至肉烂收汁。' },
{ name: '卤味拼盘', how: '鸡蛋、豆干、鸡翅加卤料包和生抽冰糖,小火卤 30 分钟,浸泡过夜更入味。' }
],
'下饭菜': [
{ name: '麻婆豆腐', how: '豆腐焯水去豆味,肉末炒香加豆瓣酱,下豆腐轻推,撒花椒粉和蒜苗。' },
{ name: '鱼香肉丝', how: '肉丝上浆滑炒,配木耳胡萝卜丝,用糖醋酱油淀粉调成鱼香汁翻炒裹匀。' },
{ name: '酸辣土豆丝', how: '土豆切丝泡水去淀粉,热油爆干辣椒花椒,大火快炒,出锅淋香醋。' },
{ name: '辣椒炒肉', how: '五花肉片煸出油,下青椒大火炒至虎皮,加豆豉和生抽,锅气足最下饭。' },
{ name: '梅干菜扣肉', how: '五花肉煮后煎皮上色切片,铺梅干菜蒸 40 分钟,倒扣脱模淋原汁。' },
{ name: '剁椒鱼头', how: '鱼头铺剁椒和姜蒜,大火蒸 10 分钟,撒葱花泼热油,鲜辣开胃。' },
{ name: '水煮肉片', how: '肉片上浆,豆芽垫底,麻辣汤底烫熟肉片连汤倒入,最后泼一勺热辣椒油。' },
{ name: '干锅花菜', how: '花菜掰小朵煎至微焦,加五花肉片、蒜片、豆瓣酱和孜然炒香。' },
{ name: '酱爆茄子', how: '茄条裹薄淀粉煎软,加黄豆酱、蒜末、少许糖炒匀,撒葱花出锅。' },
{ name: '酸豆角炒肉末', how: '酸豆角切碎挤水,与肉末、干辣椒同炒,咸香微辣,拌饭一绝。' }
],
'汤品': [
{ name: '番茄蛋花汤', how: '番茄炒出红汁加水煮开,淋入蛋液画圈,加盐、香油,撒葱花。' },
{ name: '紫菜蛋花汤', how: '水开下紫菜,关火后淋蛋液静置 5 秒再搅,加虾皮、香油和盐。' },
{ name: '冬瓜排骨汤', how: '排骨焯水后炖 30 分钟,下冬瓜块再煮 10 分钟,只加盐和姜片,清甜解腻。' },
{ name: '玉米胡萝卜汤', how: '排骨焯水,与甜玉米、胡萝卜同炖 40 分钟,出锅前加盐,无需多余调料。' },
{ name: '菌菇豆腐汤', how: '香菇、金针菇、白玉菇加水煮开,下嫩豆腐块煮 5 分钟,加盐和胡椒粉。' },
{ name: '酸辣汤', how: '木耳、笋丝、豆腐丝煮开,加生抽香醋和大量白胡椒,最后水淀粉勾芡。' },
{ name: '丝瓜蛋汤', how: '丝瓜滚刀块炒软,加水煮开淋蛋液,加盐和枸杞,清甜爽口。' },
{ name: '萝卜牛腩汤', how: '牛腩焯水与白萝卜同炖 1 小时,加姜片和八角,汤浓萝卜甜。' },
{ name: '海带豆腐汤', how: '海带结先煮 10 分钟,下豆腐煮 5 分钟,加盐、香油和蒜末。' },
{ name: '青菜丸子汤', how: '肉馅加蛋清淀粉搅上劲,挤丸子下锅煮浮起,下青菜,加盐和白胡椒。' }
],
'面食': [
{ name: '阳春面', how: '碗底放生抽、猪油、葱花,冲入高汤,面条煮熟捞入,简单却最香。' },
{ name: '番茄鸡蛋面', how: '番茄炒出汁加水煮成汤底,下面条煮熟,卧一个荷包蛋,酸香暖胃。' },
{ name: '炸酱面', how: '肉末加黄豆酱、甜面酱小火炸 10 分钟,拌上手擀面,配黄瓜丝。' },
{ name: '葱油拌面', how: '小火把葱段熬到金黄,留葱油,加生抽老抽糖调汁,拌入煮好的面条。' },
{ name: '小馄饨', how: '肉馅加姜末、蛋清搅上劲,包成小馄饨,清汤煮熟撒紫菜虾皮。' },
{ name: '韭菜鸡蛋饺子', how: '韭菜切碎拌炒散的鸡蛋,加香油和盐,包好后水开点三次凉水煮熟。' },
{ name: '红烧牛肉面', how: '牛腩炖软作浇头,面条煮熟捞碗,浇牛肉汤,加香菜和辣油。' },
{ name: '家常炒面', how: '面条煮八分熟过凉,加肉丝、青菜、豆芽大火快炒,生抽老抽调味。' },
{ name: '麻酱凉面', how: '面条煮熟过冰水,用芝麻酱、生抽、醋、蒜水调汁拌匀,加黄瓜丝。' },
{ name: '葱油饼', how: '面团抹葱油撒葱花卷起压扁,小火两面烙至金黄,分层酥脆。' }
]
};
/* ② 分类配置:顺序即转盘扇区顺序(从 12 点方向顺时针)
* bg 为扇区配色,text 为文字色,icon 为 Font Awesome 图标 */
const CATEGORIES = [
{ name: '素菜', icon: 'fa-leaf', bg: '#bbf7d0', text: '#166534' },
{ name: '荤菜', icon: 'fa-drumstick-bite', bg: '#fed7aa', text: '#9a3412' },
{ name: '下饭菜', icon: 'fa-pepper-hot', bg: '#fecaca', text: '#991b1b' },
{ name: '汤品', icon: 'fa-bowl-food', bg: '#bfdbfe', text: '#1e40af' },
{ name: '面食', icon: 'fa-bread-slice', bg: '#fde68a', text: '#92400e' }
];
const SEG = 360 / CATEGORIES.length; // 每个扇区角度:5 个分类 → 72°
const SPIN_MS = 4200; // 转动时长(毫秒)
const SPIN_TURNS = 5; // 额外整圈数,保证转动过程有充分动画
/* ---------- DOM 引用 ---------- */
const $ = id => document.getElementById(id);
const wheel = $('wheel');
let rotation = 0; // 转盘当前累计旋转角度(deg,只增不减,保证动画连贯)
let spinning = false; // 防重复点击的唯一开关
let lastPick = null; // 上一次抽中的结果 { category, dish }
/* ------------------------------------------------------------------
* ③ 绘制转盘:背景用 conic-gradient 画扇区,文字单独定位(保持水平)
* from -SEG/2 让第 0 个扇区的中心正对 12 点方向的指针
* ------------------------------------------------------------------ */
function buildWheel() {
const stops = CATEGORIES.map((c, i) => `${c.bg} ${i * SEG}deg ${(i + 1) * SEG}deg`).join(', ');
wheel.style.background = `conic-gradient(from ${-SEG / 2}deg, ${stops})`;
// 扇区中心相对 12 点方向的角度:0°, 72°, 144° ...
// 用三角函数换算成百分比坐标,标签不旋转、水平显示,手机上更好读
const R = 30; // 圆心到标签的距离(占半径百分比)
wheel.innerHTML = CATEGORIES.map((c, i) => {
const rad = (i * SEG) * Math.PI / 180;
const left = 50 + R * Math.sin(rad);
const top = 50 - R * Math.cos(rad);
return `
<div class="absolute -translate-x-1/2 -translate-y-1/2 text-center select-none pointer-events-none"
style="left:${left}%; top:${top}%">
<i class="fa-solid ${c.icon} text-[15px] sm:text-base block mb-0.5" style="color:${c.text}"></i>
<span class="block text-[13px] sm:text-sm font-semibold leading-tight" style="color:${c.text}">${c.name}</span>
</div>`;
}).join('');
}
/* 分类 chips:展示每个分类有多少道菜 */
function buildChips() {
$('catChips').innerHTML = CATEGORIES.map(c => `
<span class="inline-flex items-center gap-1 text-[11px] px-2.5 py-1 rounded-full bg-white border border-slate-200 text-slate-500">
<i class="fa-solid ${c.icon}" style="color:${c.text}"></i>${c.name}
<b class="font-semibold text-slate-700">${(DISHES[c.name] || []).length}</b>
</span>`).join('');
}
/* 菜品库速查:可折叠查看全部菜名 */
function buildLibrary() {
$('libBox').innerHTML = CATEGORIES.map(c => `
<div class="bg-white rounded-2xl shadow-card p-3.5">
<div class="flex items-center gap-2 mb-2">
<i class="fa-solid ${c.icon} text-xs" style="color:${c.text}"></i>
<span class="text-sm font-medium">${c.name}</span>
<span class="text-[11px] text-slate-400">${(DISHES[c.name] || []).length} 道</span>
</div>
<div class="flex flex-wrap gap-1.5">
${(DISHES[c.name] || []).map(d => `<span class="text-[11px] px-2 py-1 rounded-lg bg-slate-50 text-slate-600 border border-slate-100">${d.name}</span>`).join('')}
</div>
</div>`).join('');
}
/* ------------------------------------------------------------------
* ④ 抽奖逻辑
* ------------------------------------------------------------------ */
/** 计算转盘应停到的角度:使选中分类的中心对准顶部指针 */
function computeRotation(currentRotation, index) {
const cur = ((currentRotation % 360) + 360) % 360; // 归一化到 [0,360)
const target = (360 - index * SEG) % 360; // 扇区 i 中心对准指针所需的角度
let delta = target - cur;
if (delta <= 0) delta += 360; // 始终顺时针多转,避免来回摆动
// 在扇区内加一点随机偏移(±28°,扇区半宽 36°),避免每次都停在正中间,更真实
const jitter = (Math.random() * 2 - 1) * 28;
return currentRotation + SPIN_TURNS * 360 + delta + jitter;
}
/** 从分类菜品池随机取一道,尽量不与上一道重复(池子只有 1 道时除外) */
function pickDish(categoryName) {
const pool = DISHES[categoryName] || [];
if (!pool.length) return null;
let i = Math.floor(Math.random() * pool.length);
if (pool.length > 1 && lastPick && pool[i].name === lastPick.dish.name) {
i = (i + 1 + Math.floor(Math.random() * (pool.length - 1))) % pool.length;
}
return pool[i];
}
/** 开始抽奖:按钮点击的唯一入口,内部用 spinning 保证不会重复触发 */
function startSpin() {
if (spinning) return; // ★ 防重复点击
spinning = true;
setSpinUI(true);
$('resultCard').classList.add('hidden');
const index = Math.floor(Math.random() * CATEGORIES.length); // 先随机决定分类
rotation = computeRotation(rotation, index);
wheel.style.transition = `transform ${SPIN_MS}ms cubic-bezier(.16,.84,.24,1)`;
wheel.style.transform = `rotate(${rotation}deg)`;
// 动画结束后再揭晓结果(监听 transform 结束,避免其它属性误触发)
const onEnd = e => {
if (e.propertyName !== 'transform') return;
wheel.removeEventListener('transitionend', onEnd);
const category = CATEGORIES[index];
const dish = pickDish(category.name);
lastPick = { category: category.name, dish };
showResult(category, dish);
spinning = false;
setSpinUI(false);
};
wheel.addEventListener('transitionend', onEnd);
}
/** 转动中禁用按钮并切换图标文案 */
function setSpinUI(isSpinning) {
$('btnSpin').disabled = isSpinning;
$('btnCenter').disabled = isSpinning;
$('spinText').textContent = isSpinning ? '转盘转动中...' : '开始抽奖';
$('spinIcon').className = isSpinning ? 'fa-solid fa-spinner fa-spin' : 'fa-solid fa-rotate';
$('centerIcon').className = isSpinning ? 'fa-solid fa-spinner fa-spin text-lg' : 'fa-solid fa-play text-lg';
$('btnSpin').classList.toggle('spin-ready', !isSpinning);
}
/** 展示结果卡片:菜名 + 家常做法 */
function showResult(category, dish) {
if (!dish) return;
$('resIcon').style.background = category.bg;
$('resIcon').style.color = category.text;
$('resIcon').innerHTML = `<i class="fa-solid ${category.icon}"></i>`;
$('resDish').textContent = dish.name;
$('resCat').textContent = category.name;
$('resCat').style.background = category.bg;
$('resCat').style.color = category.text;
$('resHow').textContent = dish.how;
const card = $('resultCard');
card.classList.remove('hidden');
card.classList.remove('animate-pop');
void card.offsetWidth; // 强制重排,使动画能重复播放
card.classList.add('animate-pop');
card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
/* ------------------------------------------------------------------
* ⑤ 交互绑定
* ------------------------------------------------------------------ */
$('btnSpin').addEventListener('click', startSpin); // 主按钮
$('btnCenter').addEventListener('click', startSpin); // 中心圆按钮
// 换一道:不转转盘,直接在当前分类里重抽
$('btnReroll').addEventListener('click', () => {
if (spinning || !lastPick) return;
const category = CATEGORIES.find(c => c.name === lastPick.category);
const dish = pickDish(lastPick.category);
lastPick = { category: lastPick.category, dish };
showResult(category, dish);
});
// 再转一次:重新走完整转盘流程
$('btnAgain').addEventListener('click', startSpin);
// 菜品库折叠
$('btnToggleLib').addEventListener('click', () => {
const box = $('libBox');
box.classList.toggle('hidden');
$('libArrow').style.transform = box.classList.contains('hidden') ? '' : 'rotate(180deg)';
});
// 空格键也能转(PC 便利)
document.addEventListener('keydown', e => {
if (e.code === 'Space' && !spinning) { e.preventDefault(); startSpin(); }
});
/* ---------- 初始化 ---------- */
buildWheel();
buildChips();
buildLibrary();
setSpinUI(false);
</script>
</body>
</html>