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

HTML Canvas无法绘图求助:JS绘图应用无绘制内容

Canvas绘图无内容的问题修复方案

问题根源分析

你的代码里存在几个核心问题,导致Canvas无法正常绘制:

  • 错误设置Canvas尺寸:你给绘图上下文ctx设置width和height,但这两个属性不属于2D绘图上下文,应该直接设置canvas元素本身的width和height属性。否则Canvas会沿用默认的300x150尺寸,你的绘制内容要么超出可视区域,要么被压缩变形。
  • 缺少鼠标移动事件监听:当前仅在mousedown时调用一次draw函数,但绘图需要在鼠标移动过程中持续触发绘制逻辑,所以必须添加mousemove事件监听。
  • 鼠标坐标未转换为Canvas相对坐标:e.clientX/clientY是相对于浏览器视口的坐标,不是Canvas内部的相对坐标。如果Canvas存在布局偏移,绘制位置会完全偏离预期,需要通过getBoundingClientRect()转换坐标。
  • React组件中使用window.load事件不合适:React组件渲染时,window可能已经完成加载,导致handleCanvas函数不会执行。应该用React的useEffect钩子替代,确保组件挂载后执行初始化逻辑。

修复后的完整代码

import { useEffect } from 'react';

function CanvasItem({index}){
    let drawing = false;
    let ctx = null;

    useEffect(() => {
        const canv = document.getElementById(`canvas-item-${index}`);
        if (!canv) return;

        ctx = canv.getContext('2d');
        if (!ctx) return;

        // 设置Canvas实际尺寸与显示尺寸
        function setCanvasSize() {
            const size = window.innerHeight * 9/100;
            // 设置Canvas实际绘图尺寸(决定分辨率)
            canv.width = size;
            canv.height = size;
            // 设置Canvas显示尺寸(控制页面上的大小)
            canv.style.width = `${size}px`;
            canv.style.height = `${size}px`;
        }

        setCanvasSize();
        window.addEventListener('resize', setCanvasSize);

        // 绑定绘图相关事件
        canv.addEventListener('mousedown', startedDrawing);
        canv.addEventListener('mouseup', finishedDrawing);
        canv.addEventListener('mousemove', draw);
        canv.addEventListener('mouseleave', finishedDrawing); // 鼠标移出Canvas时结束绘制

        // 组件卸载时清理事件监听,避免内存泄漏
        return () => {
            window.removeEventListener('resize', setCanvasSize);
            canv.removeEventListener('mousedown', startedDrawing);
            canv.removeEventListener('mouseup', finishedDrawing);
            canv.removeEventListener('mousemove', draw);
            canv.removeEventListener('mouseleave', finishedDrawing);
        };
    }, [index]);

    function startedDrawing(e){
        drawing = true;
        console.log("started drawing");
        // 初始化绘图路径起点
        const rect = e.target.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        ctx.beginPath();
        ctx.moveTo(x, y);
    }

    function finishedDrawing(){
        drawing = false;
        console.log("finished drawing");
        ctx.beginPath();
    }

    function draw(e){
        if(!drawing) return;

        // 转换为Canvas内部相对坐标
        const rect = e.target.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;

        ctx.lineWidth = 1;
        ctx.lineCap = 'round';
        ctx.strokeStyle = 'red';

        ctx.lineTo(x, y);
        ctx.stroke();
        ctx.beginPath();
        ctx.moveTo(x, y);
    }

    return (
        <canvas id={`canvas-item-${index}`} className="canvas-item"></canvas>
    )
}

修复关键点说明

  1. 用useEffect替代window.load,确保组件挂载后初始化Canvas,同时通过返回清理函数移除事件监听,避免内存泄漏。
  2. 分别设置Canvas的width/height(绘图分辨率)和style.width/style.height(页面显示大小),保证绘制清晰且尺寸符合预期。
  3. 添加mousemove事件监听,实现鼠标移动过程中的持续绘制。
  4. 转换鼠标坐标为Canvas内部相对坐标,确保绘制位置准确。
  5. 新增mouseleave事件监听,防止鼠标移出Canvas区域后仍继续绘制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:15:29