Canvas需手动实现悬停效果:1.监听mousemove并转换坐标,用命中检测判断图形悬停;2.用requestAnimationFrame配合插值实现平滑缩放;3.通过shadowBlur与shadowColor动态设置发光;4.所有状态更新与重绘分离以保证60fps流畅性。

Canvas 本身不自带事件监听(比如 hover),必须手动通过 mousemove + 坐标计算 + 图形边界判断,来模拟“悬停”效果;缩放与发光需在每帧重绘中动态调整图形参数并叠加高斯模糊(用 shadowBlur)或叠加光晕图层。
1. 捕获鼠标位置并判断是否悬停在目标图形上
Canvas 是位图绘制环境,没有 DOM 元素的概念,所以不能直接用 :hover。你需要:
- 监听
canvas的mousemove事件,用getBoundingClientRect()将屏幕坐标转为 Canvas 坐标 - 对每个可交互图形(如矩形、圆形),写一个「命中检测」函数(例如:点是否在圆内、是否在矩形范围内)
- 维护一个状态变量(如
isHovered),在检测成立时设为true,否则false
示例(圆形):
const rect = canvas.getBoundingClientRect();
canvas.addEventListener('mousemove', (e) => {
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const dx = x - centerX;
const dy = y - centerY;
isHovered = Math.sqrt(dx*dx + dy*dy) < radius;
});2. 实现平滑缩放:用插值过渡代替突变
直接切换缩放比例会显得生硬。推荐用简单缓动(如线性插值)让 scaleFactor 逐步趋近目标值:
立即学习“前端免费学习笔记(深入)”;
- 定义两个值:
targetScale(悬停时为 1.2,离开时为 1.0)和currentScale(当前实际缩放) - 在动画循环(
requestAnimationFrame)中更新:currentScale += (targetScale - currentScale) * 0.1; - 绘制时用
ctx.save(); ctx.scale(currentScale, currentScale); ... ctx.restore();
3. 添加发光反馈:用 shadowBlur + shadowColor 模拟光晕
Canvas 原生不支持 CSS 式的 box-shadow,但可通过阴影属性实现类似效果:
- 在绘制图形前设置:
ctx.shadowBlur = isHovered ? 20 : 5; ctx.shadowColor = isHovered ? 'rgba(100, 180, 255, 0.8)' : 'rgba(0,0,0,0.2)';- 注意:阴影会影响后续所有绘制,记得在不需要时调用
ctx.shadowBlur = 0;清除 - 若需更精准光晕(如外扩轮廓),可先用
clip()或二次绘制带偏移的描边
4. 必须配合 requestAnimationFrame 实现流畅动画
不要在 mousemove 中直接重绘——频繁触发会导致卡顿。正确做法是:
- 只在
mousemove中更新状态(isHovered、targetScale等) - 用
requestAnimationFrame驱动主绘制循环,每次清空画布、重新计算缩放/阴影、再绘制图形 - 这样能稳定维持 60fps,缩放和发光都自然连贯



















