Canvas 实现带点击反馈的 UI 按钮组需构建绘制、坐标映射、状态响应与视觉反馈闭环:缓存按钮边界数据并统一配置样式参数;手动映射鼠标坐标检测点击;通过 requestAnimationFrame 实现轻量缩放与颜色变化反馈;依托外部状态对象驱动互斥、禁用等交互逻辑,并可扩展键盘支持。

Canvas 绘制带点击反馈的 UI 按钮组,核心不是“画完就完”,而是把绘制、坐标映射、状态响应和视觉反馈串成闭环。它不依赖 Unity 的 CanvasGroup 或 HTML 的 button 标签,而靠纯代码控制像素级交互逻辑——适合轻量 Web 应用、教学工具、或需要高度定制化外观的嵌入式界面。
按钮绘制与坐标管理
每个按钮本质是 Canvas 上一段可识别的图形区域(矩形、圆角矩形或路径),需明确记录其边界信息:
- 绘制时用
ctx.fillRect()或ctx.roundRect()(若支持),同时缓存该按钮的{x, y, width, height, id}数据 - 避免硬编码尺寸,推荐统一配置按钮间距、圆角半径、内边距,便于后续缩放或主题切换
- 文字居中显示:用
ctx.textAlign = 'center'和ctx.textBaseline = 'middle',配合ctx.measureText().width避免文字溢出
点击检测与事件分发
Canvas 本身不提供元素级事件,必须手动将鼠标/触摸坐标映射到按钮区域:
- 监听
canvas.addEventListener('click', handler),用getBoundingClientRect()计算画布在视口中的位置 - 通过
event.clientX - rect.left得到相对于画布左上角的坐标(x, y) - 遍历所有按钮数据,用
x > btn.x && x btn.y && y 判断是否命中 - 命中后触发对应回调(如
onButtonClick(btn.id)),并标记当前按钮为“被点击”状态
视觉反馈实现方式
点击反馈要即时、可感知,但不能打断主流程。推荐用轻量动画替代 CSS 类切换:
- 按下时:缩小按钮至 0.95 倍,并加深背景色(如从 #4285F4 → #3367D6)
- 松开时:100ms 内恢复原尺寸和颜色,用
requestAnimationFrame控制帧率 - 若需长按效果,可结合
mousedown+setTimeout+mouseup监听组合判断 - 避免在每次绘制中重复计算——只在状态变更时重绘受影响的按钮区域(局部刷新比全屏 clear 更高效)
状态同步与多按钮协作
按钮组常需互斥(单选)、联动(启用/禁用)或批量响应,靠外部状态驱动绘制:
- 维护一个状态对象,例如
{activeId: 'save', disabledIds: ['export']} - 绘制时根据状态决定样式:禁用按钮用灰色 + 低透明度(
ctx.globalAlpha = 0.5),激活按钮加描边或阴影 - 点击某按钮后,自动更新状态并触发重绘;也可向外暴露
setState()方法供业务逻辑调用 - 键盘支持(如 Tab 切换、Enter 确认)需额外绑定
keydown,用focusIndex跟踪当前焦点按钮











