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

动态生成的多个canvas仅支持单画布绘制的解决方案求助

问题原因
  • 你声明的canvas、ctx以及坐标、绘制状态变量都是全局作用域,循环给多个canvas绑定事件的时候,这些全局变量会被后续循环的值覆盖,最终所有事件触发时用的都是最后一个canvas的上下文和状态,所以只能在一个画布上绘制。
解决方案

核心思路是把每个画布的上下文、绘制状态和事件逻辑独立封装,不要用全局变量共享状态。

修改后的代码示例

HTML部分动态生成canvas的逻辑无需调整,保证id为can_xxx的格式即可,JS代码修改如下:

function init() {
  // 如果canvas是动态生成的,也可以直接用document.querySelectorAll('canvas')获取所有画布,不用固定循环范围
  for(let i=1;i<3;i++){
    const canvas = document.getElementById('can_'+i);
    const ctx = canvas.getContext("2d");
    // 每个画布独立维护状态变量,不会互相覆盖
    let flag = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dot_flag = false;
    const strokeColor = "red";
    const lineWidth = 2;

    // 绘制函数封装在循环内,使用当前画布的ctx实例
    function draw() {
      ctx.beginPath();
      ctx.moveTo(prevX, prevY);
      ctx.lineTo(currX, currY);
      ctx.strokeStyle = strokeColor;
      ctx.lineWidth = lineWidth;
      ctx.stroke();
      ctx.closePath();
    }

    // 坐标计算逻辑也封装在内,直接使用当前循环的canvas实例
    function findxy(res, e) {
      const rect = canvas.getBoundingClientRect();
      if (res == 'down') {
        prevX = currX;
        prevY = currY;
        currX = e.clientX - rect.left;
        currY = e.clientY - rect.top;

        flag = true;
        dot_flag = true;
        if (dot_flag) {
          ctx.beginPath();
          ctx.fillStyle = strokeColor;
          ctx.fillRect(currX, currY, 2, 2);
          ctx.closePath();
          dot_flag = false;
        }
      }
      if (res == 'up' || res == "out") {
        flag = false;
      }
      if (res == 'move') {
        if (flag) {
          prevX = currX;
          prevY = currY;
          currX = e.clientX - rect.left;
          currY = e.clientY - rect.top;
          draw();
        }
      }
    }

    // 绑定事件使用当前画布对应的findxy逻辑
    canvas.addEventListener("mousemove", function (e){
      findxy('move', e)
    }, false);
    canvas.addEventListener("mousedown", function (e) {
      findxy('down', e)
    }, false);
    canvas.addEventListener("mouseup", function (e) {
      findxy('up', e)
    }, false);
    canvas.addEventListener("mouseout", function (e) {
      findxy('out', e)
    }, false);
  }
}

优化说明

  • 所有和单个画布相关的状态、方法都封装在循环的块级作用域内,每个画布的状态完全独立,不会互相干扰
  • 提前缓存getBoundingClientRect()的调用结果,避免重复计算提升性能
  • 后续如果要新增更多canvas,只需要调整循环逻辑或者直接遍历所有canvas元素即可,无需修改核心绘制逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 06:51:02