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

Svelte自定义组件内Canvas绘图不生效问题如何解决?

问题原因

核心问题出在Svelte的响应式更新规则和canvas的特性上:

  1. Svelte只有在对变量执行赋值操作时才会触发响应式更新,你修改的是普通对象canvas的内部属性,没有触发赋值操作,因此<canvas>元素的width、height属性始终是初始化时的1000x1000,不会同步为你设置的body尺寸。
  2. 当canvas的画布尺寸和实际展示尺寸不一致时,绘制的内容会被拉伸/挤压,甚至可能因为canvas元素超出视口导致你看不到左上角绘制的小矩形。
  3. 你将代码移到App.svelte能正常运行,是因为顶层组件的更新触发逻辑和子组件存在差异,刚好触发了宽高的同步,这属于不可靠的巧合,不是正确的用法。

解决方法

方法1:直接操作canvas元素的宽高属性(推荐)

不需要通过中间对象传递宽高,直接操作绑定的canvas DOM元素属性,符合canvas的原生使用习惯,逻辑最简洁:

<script>
  import { onMount } from 'svelte';

  let canvasEl;

  const drawRect = (context) => {
    context.beginPath();
    context.fillStyle = '#000000';
    context.rect(0, 0, 40, 10);
    context.fill();
  };

  onMount(() => {
    const context = canvasEl.getContext('2d');
    // 直接修改元素的宽高属性,修改后画布尺寸会立即更新
    canvasEl.width = document.body.clientWidth;
    canvasEl.height = document.body.clientHeight;
    drawRect(context);
  });
</script>

<canvas bind:this={canvasEl} />

方法2:主动触发响应式更新

如果你需要保留中间的canvas配置对象用于其他场景,可以修改完属性后主动触发响应式更新,注意要等DOM更新完成后再执行绘制,避免宽高变更清空画布内容:

<script>
  import { onMount, tick } from 'svelte';

  let canvasEl;
  let canvas = {
    width: 1000,
    height: 1000
  };

  const drawRect = (context) => {
    context.beginPath();
    context.fillStyle = '#000000';
    context.rect(0, 0, 40, 10);
    context.fill();
  };

  onMount(async () => {
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    // 主动赋值触发响应式更新
    canvas = canvas;
    // 等待DOM更新完成
    await tick();
    
    const context = canvasEl.getContext('2d');
    drawRect(context);
  });
</script>

<canvas bind:this={canvasEl} width={canvas.width} height={canvas.height} />

内容的提问来源于stack exchange,提问作者kota-yata

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:15:08