Files
vscode-workbench/.trae/documents/图片编辑器移动端适配.md
T

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 添加触摸优化样式

验证步骤

  1. 运行 TypeScript 编译检查:npx tsc --noEmit
  2. 启动开发服务器:npm run dev
  3. 在移动设备或浏览器开发者工具中测试:
    • 画笔工具:手指在画布上滑动应该能绘制线条
    • 文本工具:手指点击画布应该能放置文本
    • 其他功能(亮度、滤镜等)应该正常工作

注意事项

  • 触摸事件需要 e.preventDefault() 阻止默认行为(如页面滚动)
  • touch-action: none 防止浏览器处理触摸手势
  • 坐标转换需要考虑 Canvas 的缩放比例
  • 触摸事件使用 e.touches[0] 获取第一个触摸点