用canvas实现涂鸦需三步:监听鼠标/触摸事件并preventDefault防滚动,用beginPath()+lineTo()+stroke()绘线且设lineCap/lineJoin为'round',清屏用clearRect()而非重设width以保状态。

怎么用 canvas 实现基础涂鸦功能
直接上手:核心就是监听鼠标/触摸事件,把移动轨迹连成线段。别碰 document.write 或用 div 拼线条——性能会崩,而且没法抗锯齿。
关键三步:
- 用
getContext('2d')拿到绘图上下文,设好lineCap和lineJoin为'round',否则线条接头是尖角或断开 - 鼠标按下(
mousedown)时记录起点,同时设isDrawing = true - 移动中(
mousemove)且isDrawing为真时,调用lineTo(x, y)+stroke();注意每次画前要beginPath(),否则所有历史路径都会重绘
漏掉 beginPath() 是新手最常踩的坑:画几笔后整块画布变卡,因为每次 stroke 都在重绘全部路径。
touchstart/touchmove 怎么兼容移动端
PC 端靠鼠标事件够用,但手机必须处理触摸事件,且不能只加监听——默认行为会触发页面滚动,线条会断、坐标偏移。
立即学习“前端免费学习笔记(深入)”;
实操要点:
- 给
canvas绑定touchstart、touchmove、touchend,并在每个事件回调里调用event.preventDefault() - 获取触摸点坐标别用
clientX/Y,改用touches[0].clientX,否则多指操作会乱 - 注意视口缩放:用
canvas.getBoundingClientRect()动态算出当前 canvas 的实际显示尺寸,再按比例换算触摸坐标,否则在 iPhone 上画歪是常态
不处理 preventDefault,轻则线条跳变,重则手指一划页面就滚走。
为什么清空画布用 clearRect() 而不是重设 width
很多人写 canvas.width = canvas.width 来清屏,看着能清,但副作用极隐蔽:
- 会重置所有上下文状态:线宽、颜色、阴影、变换矩阵全丢,下次画还得重设
- 触发 canvas 重建,对高分辨率屏(如 Retina)可能丢失像素比适配逻辑
- 在频繁擦除场景下(比如橡皮擦),性能比
clearRect(0,0,w,h)差一截
正确做法是先用 getBoundingClientRect() 拿到显示区域宽高,再用 devicePixelRatio 换算真实 canvas 像素尺寸,最后传给 clearRect()。硬写死宽高数,缩放后就留白或裁剪。
橡皮擦和颜色切换怎么不卡顿
橡皮擦不是“画白色”,而是用 globalCompositeOperation = 'destination-out' —— 这样擦的是 canvas 像素本身,不依赖背景色,也不会因抗锯齿残留毛边。
- 切工具(笔/橡皮/选色)时,只改上下文属性,别反复调用
beginPath()或清空路径栈 - 颜色用
strokeStyle设置,别用fillStyle混着来;透明度控制统一走globalAlpha,别在颜色字符串里写rgba(),后者每次解析有开销 - 高频绘制时(如快速滑动),用
requestAnimationFrame聚合多次stroke()调用,避免帧率骤降
真正难的不是画出来,是让连续手势不丢点、不卡、不糊——这些细节堆起来,才是「能上线」和「用户愿意多画两笔」的分界线。



















