必须在每次绘制前显式设置ctx.linewidth=currentwidth,配合事件绑定、状态同步和防抖重绘;按钮共享单一数据源currentlinewidth,pointerdown初始化路径,pointermove追加点,避免linewidth失效或线条跳变。

直接用按钮控制 ctx.lineWidth 就行,但别只改值——必须配合事件绑定、状态同步和防抖重绘,否则点击无效或线条跳变。
按钮点击后 lineWidth 不生效?检查 ctx 是否被重置
常见错误是每次绘制都重新调用 beginPath() 且没在 stroke 前设置 lineWidth。Canvas 的样式(包括 lineWidth)是上下文状态,不是“全局默认”,一旦 beginPath() 后没设,就沿用上次值或初始值(1.0)。
- 确保每个绘制操作前都显式设置
ctx.lineWidth = currentWidth,不能只在按钮里赋值就完事 - 避免在
pointermove中反复调beginPath()+moveTo()+lineTo()+stroke()—— 这会清空路径并重绘单点,导致粗细不连续 - 推荐做法:累积坐标点数组,在
pointerup或节流后的pointermove中批量绘制,此时统一用当前currentWidth
如何让多个按钮共享并响应同一个 lineWidth 状态
按钮本身不存状态,得靠一个变量(如 let currentLineWidth = 3)作为单一数据源,所有按钮点击都更新它,绘制逻辑读它。
- 给每个按钮加
data-width属性,比如<button data-width="1">细</button>、<button data-width="8">粗</button> - 统一绑定 click 事件:
document.querySelectorAll('[data-width]').forEach(btn => btn.addEventListener('click', () => { currentLineWidth = parseFloat(btn.dataset.width); })) - 别用内联
onclick="currentLineWidth=5"—— 难维护、易污染全局、无法复用
为什么按钮点了但线条还是细?可能是绘制路径没重置
Canvas 路径是累积的。stroke() 不会自动清空路径,如果上一次画的是细线、这次想画粗线但没调 beginPath(),就会把新旧点混在一起,lineWidth 只对本次 stroke() 生效,但路径里可能还带着旧点的“记忆”。
- 每次开始新笔画(
pointerdown)时必须调ctx.beginPath() - 不要在
pointermove里每帧都beginPath()—— 改成只在pointerdown初始化路径,pointermove只追加lineTo() - 若需实时预览粗细变化(比如悬停按钮时画布上显示对应粗细的测试线),单独开一个临时
ctx绘制,别污染主绘图路径
移动端按钮点击延迟或失效?优先用 pointer 事件而非 click
在 iPad 或 Android 触控设备上,click 有约 300ms 延迟,且可能被 canvas 的 preventDefault() 拦截;pointerdown 更可靠,兼容触笔/手指/鼠标。
- 绑定事件用
btn.addEventListener('pointerdown', handler, { passive: false }) -
passive: false允许你在 handler 里调e.preventDefault()(防止页面滚动干扰) - 避免同时监听
click和pointerdown—— 会导致双触发,尤其在桌面 Chrome 上
真正麻烦的不是设 lineWidth,而是让粗细变化在连续笔迹中平滑过渡——这需要你把“宽度”当作路径属性的一部分来存储,而不是上下文全局状态。比如记录每段线的起点、终点、宽度,重绘时逐段应用,否则快速切换按钮时中间那段永远卡在旧宽度上。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











