4.9 KiB
4.9 KiB
图片编辑器移动端适配
摘要
为图片编辑器(ImageEditor)添加移动端触摸事件支持,使画笔和文本工具能在移动设备上使用。
当前状态分析
核心问题
Canvas 元素只绑定了鼠标事件,未绑定触摸事件:
// 当前实现 - 仅支持鼠标
<canvas
onClick={handleCanvasClick} // 鼠标点击
onMouseDown={handleMouseDown} // 鼠标按下
onMouseMove={handleMouseMove} // 鼠标移动
onMouseUp={handleMouseUp} // 鼠标抬起
/>
受影响功能
- 画笔工具: 无法在触摸屏上绘画
- 文本工具: 无法在触摸屏上点击放置文本
实施步骤
步骤 1:添加触摸坐标获取函数
在 ImageEditor.tsx 中添加通用的位置获取函数:
// 获取鼠标或触摸位置
const getEventPosition = (e: React.MouseEvent<HTMLCanvasElement> | React.TouchEvent<HTMLCanvasElement>) => {
const canvas = canvasRef.current;
if (!canvas) return null;
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
let clientX: number, clientY: number;
if ('touches' in e) {
const touch = e.touches[0] || e.changedTouches[0];
if (!touch) return null;
clientX = touch.clientX;
clientY = touch.clientY;
} else {
clientX = e.clientX;
clientY = e.clientY;
}
return {
x: (clientX - rect.left) * scaleX,
y: (clientY - rect.top) * scaleY,
};
};
步骤 2:添加触摸事件处理函数
// 触摸开始
const handleTouchStart = (e: React.TouchEvent<HTMLCanvasElement>) => {
e.preventDefault();
const pos = getEventPosition(e);
if (!pos) return;
if (activeTool === "brush") {
setIsDrawing(true);
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
ctx.strokeStyle = brushColor;
ctx.lineWidth = brushSize;
ctx.lineCap = "round";
ctx.lineJoin = "round";
}
};
// 触摸移动
const handleTouchMove = (e: React.TouchEvent<HTMLCanvasElement>) => {
e.preventDefault();
if (!isDrawing || activeTool !== "brush") return;
const pos = getEventPosition(e);
if (!pos) return;
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
};
// 触摸结束
const handleTouchEnd = (e: React.TouchEvent<HTMLCanvasElement>) => {
e.preventDefault();
if (isDrawing) {
setIsDrawing(false);
saveHistory();
}
};
步骤 3:修改文本工具点击处理
const handleCanvasTouchTap = (e: React.TouchEvent<HTMLCanvasElement>) => {
e.preventDefault();
if (activeTool !== "text" || !textInput.trim()) return;
const pos = getEventPosition(e);
if (!pos) return;
const newText: TextItem = {
id: Math.random().toString(36).substring(2, 9),
text: textInput,
x: pos.x,
y: pos.y,
fontSize: textSize,
color: textColor,
};
setTexts((prev) => [...prev, newText]);
saveHistory();
};
步骤 4:更新 Canvas JSX
<canvas
ref={canvasRef}
className={`ie-canvas ${activeTool === "text" ? "text-cursor" : ""} ${activeTool === "brush" ? "brush-cursor" : ""}`}
onClick={handleCanvasClick}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseUp}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onClick={activeTool === "text" ? handleCanvasClick : undefined}
onTouchStart={activeTool === "text" ? handleCanvasTouchTap : handleTouchStart}
/>
步骤 5:添加 CSS 触摸优化
在 ImageEditor.css 中添加:
/* 防止浏览器默认触摸行为 */
.ie-canvas {
touch-action: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
}
/* 移动端画布区域优化 */
@media (max-width: 768px) {
.ie-canvas {
max-width: 100%;
height: auto;
}
.ie-tool-btn {
min-width: 48px;
min-height: 48px;
}
}
涉及的文件
| 文件 | 操作 |
|---|---|
src/pages/ImageEditor/ImageEditor.tsx |
添加触摸事件处理函数和位置获取函数 |
src/pages/ImageEditor/ImageEditor.css |
添加触摸优化样式 |
验证步骤
- 运行 TypeScript 编译检查:
npx tsc --noEmit - 启动开发服务器:
npm run dev - 在移动设备或浏览器开发者工具中测试:
- 画笔工具:手指在画布上滑动应该能绘制线条
- 文本工具:手指点击画布应该能放置文本
- 其他功能(亮度、滤镜等)应该正常工作
注意事项
- 触摸事件需要
e.preventDefault()阻止默认行为(如页面滚动) touch-action: none防止浏览器处理触摸手势- 坐标转换需要考虑 Canvas 的缩放比例
- 触摸事件使用
e.touches[0]获取第一个触摸点