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

迁移至Laravel后Canvas无法正常绘制图片问题咨询

问题描述

我有一个无框架的原生前端项目原本运行正常:页面展示多张照片,点击任意照片会弹出模态框,照片会渲染在模态框内的canvas画布上。
以下是打开imageModal模态框、将照片绘制到名为photoImage的canvas上的JS代码,参数e代表被点击的图片元素:

var canvas = document.getElementById("photoImage");
var canvasCtx = canvas.getContext("2d");

function viewPhoto(e) {
    $("#imageModal").modal("show");

    var image = new Image();
    image.src = e.src;

    canvas.width = image.width; // 宽度设置不生效
    canvas.height = image.height;  // 高度设置不生效
    canvasCtx.drawImage(image, 0, 0);  // 照片无法绘制
}

把完全相同的代码迁移到Laravel项目后,照片没法正常绘制到canvas上。我对比过两个项目的canvas属性,完全一致:两个项目都能正确拿到图片的height属性,但Laravel项目里这个值改不了canvas的实际尺寸。
问题示例截图


根本原因

这个问题和Laravel框架没有直接关系,核心是代码存在异步时序错误,原项目能正常运行完全是浏览器缓存带来的巧合:

  • 浏览器加载Image对象的资源是异步行为,给image.src赋值后,浏览器会发起资源请求,此时图片还没加载完成,直接读取image.width/image.height拿到的是默认值0,自然没法正确设置canvas尺寸、绘制图片。
  • 原项目能跑通,是因为页面上已经展示了对应缩略图,图片资源早就被浏览器缓存了,给Image对象设置同源缓存地址时,浏览器会直接同步返回缓存资源,此时立刻读宽高能拿到正确值。迁移到Laravel项目后,大概率是响应头配置、资源路径、缓存策略和原项目有差异,图片资源没有命中即时缓存,异步加载的时序问题就暴露出来了。

另外还有个次要影响因素:Bootstrap模态框在调用modal('show')的瞬间还处于隐藏状态,部分浏览器对display: none状态下的canvas做尺寸修改、绘制操作时,会出现渲染不生效的问题。

修复方法

调整代码逻辑,等两个前置条件满足后再操作canvas:一是图片资源加载完成,二是模态框完全显示(兼容极端浏览器渲染问题),修复后代码如下:

const canvas = document.getElementById("photoImage");
const canvasCtx = canvas.getContext("2d");

function viewPhoto(e) {
    $("#imageModal").one("shown.bs.modal", function () {
        const image = new Image();
        // 注意:必须先绑定onload回调,再设置src,避免缓存场景下错过load事件
        image.onload = function () {
            canvas.width = image.width;
            canvas.height = image.height;
            canvasCtx.drawImage(image, 0, 0);
        }
        image.src = e.src;
    }).modal("show");
}

两个关键注意点:

  • 永远先给Image对象绑定onload回调,再设置src属性,否则如果资源已经被缓存,load事件可能在绑定回调前就触发,导致回调永远不执行。
  • 用one而不是on绑定模态框事件,避免每次点击都重复绑定回调,造成内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:18:16