You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js开发Canvas绘图应用触摸事件定位偏移300px问题求助

问题根源

你的触摸偏移问题核心是坐标计算逻辑错误:当前使用的pageX/pageY是相对于整个文档顶部的坐标,配合offsetLeft/offsetTop(仅相对于最近定位父元素的偏移)的计算方式没有考虑页面滚动、父元素定位、Canvas缩放等影响,所以会出现固定偏移量的问题。


完整修复方案

修复要点

  • 重写坐标计算函数touchPose,使用clientX/clientY结合Canvas元素的getBoundingClientRect()计算相对坐标,同时兼容Canvas CSS缩放场景
  • 优化drawLine的属性设置顺序,保证线条圆角属性生效
  • 修正冗余的DOM选择逻辑,直接用Vue的ref获取Canvas实例
  • 修正模板拼写错误

修复后代码

模板部分
<template>
    <canvas ref="Canvas" id="canvas" width="350" height="350"></canvas>
</template>
逻辑部分
const Canvas = ref(null);
const state = reactive({
  canvas: null,
  isDrawing: false,
  X: 0,
  Y: 0,
})

onMounted(() => {
  // 直接用ref获取canvas实例,不需要重复querySelector
  const canvas = Canvas.value
  const context = canvas.getContext('2d')
  state.canvas = context
  canvas.addEventListener('touchstart', beginTouchDrawing, false);
  canvas.addEventListener('touchmove', TouchDrawing, false);
})

// 修正后的坐标计算逻辑
function touchPose(e){
  if (e.touches?.length === 1) {
    const touch = e.touches[0]
    const canvasRect = touch.target.getBoundingClientRect()
    // 计算Canvas的缩放比例,兼容CSS自适应缩放场景
    const scaleX = touch.target.width / canvasRect.width
    const scaleY = touch.target.height / canvasRect.height
    // 坐标先转视口相对,再转Canvas内部相对,乘以缩放比例得到精准绘图坐标
    const x = (touch.clientX - canvasRect.left) * scaleX
    const y = (touch.clientY - canvasRect.top) * scaleY
    return [x, y]
  }
  return [0,0]
}

function beginTouchDrawing(event) {
  state.isDrawing = true
  const pos = touchPose(event)
  drawLine(pos[0], pos[1], pos[0], pos[1])
  state.X = pos[0];
  state.Y = pos[1];
  event.preventDefault();
}

function TouchDrawing(event) {
  if (state.isDrawing) {
    const pose = touchPose(event)
    drawLine(state.X, state.Y, pose[0], pose[1]);
    state.X = pose[0];
    state.Y = pose[1];
    event.preventDefault();
  }
}

// 修正属性顺序,保证lineCap生效
function drawLine(X, Y, newX, newY){
  const ctx = state.canvas
  if(!ctx) return
  ctx.lineWidth = 10;
  ctx.lineCap = 'round'; // 移到stroke之前才会对当前绘制生效
  ctx.beginPath();
  ctx.moveTo(X, Y);
  ctx.lineTo(newX, newY);
  ctx.stroke();
  ctx.closePath();
}

内容的提问来源于stack exchange,提问作者Porfinogeneta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 23:36:04