FabricJS画布已存图像实例却仅渲染文本框、导出无图像问题
渲染异常的根本原因
- 问题出在图片加载的时序错位。代码执行添加Fabric图像的逻辑时,网络上的测试图片还没完成加载,传入
fabric.Image构造函数的DOM图像元素此时没有任何有效像素内容,对应的naturalWidth、naturalHeight属性都是0。 - 因为图像实例已经正常创建,并且被加入了画布的对象存储列表,所以控制台打印画布内容时可以看到两个对象,但因为没有可绘制的图像像素,不管是画布正常渲染,还是调用
toDataURL导出图像,这个实例都不会生成可见内容。 - 你之前给img标签加的
crossorigin="anonymous"配置只是解决跨域画布污染的权限问题,允许跨域图片被绘制到canvas上,但这个配置完全不影响图片本身的加载时序,解决不了当前的渲染问题。
修复实现方式
两种经过验证的可用方案,任选其一即可:
- 方案1:等待原生图片加载完成后,再创建Fabric图像实例
给DOM上的img元素绑定load事件,等图片内容完全加载完成,再执行Fabric图像的创建、添加逻辑,后续的文本框添加、画布导出操作也要放在这个加载完成的回调里,保证执行顺序正确。对应的核心代码片段:var imgEle = $("#testImg")[0]; imgEle.onload = function() { // 图片加载完成后再创建Fabric图像 var newImg = new fabric.Image(imgEle, { left: 0, top: 0 }); canvas.add(newImg); var newTextBox = new fabric.Textbox("Hello text box", { left: 0, top: 100, width: 200 }); canvas.add(newTextBox); canvas.renderAll(); // 再执行导出逻辑 var canvasUrl = canvas.toDataURL('png'); var canvasImg = $("<img id=canvasImg>"); canvasImg.attr('src', canvasUrl); canvasImg.appendTo("#render"); } - 方案2:使用Fabric内置的图像加载API
不需要手动引用DOM中的img元素,直接调用Fabric提供的fabric.Image.fromURL方法,这个方法会自动处理图片加载等待、跨域权限配置,等图片加载完成后会在回调中返回已经准备好的图像实例,直接添加到画布即可,不需要自己手写图片加载监听逻辑。对应的核心代码片段:// 自动处理加载与跨域配置 fabric.Image.fromURL('https://picsum.photos/seed/123/50/50', function(newImg) { newImg.set({ left: 0, top: 0 }); canvas.add(newImg); canvas.renderAll(); // 文本框添加、导出逻辑同样放在回调内执行 var newTextBox = new fabric.Textbox("Hello text box", { left: 0, top: 100, width: 200 }); canvas.add(newTextBox); canvas.renderAll(); var canvasUrl = canvas.toDataURL('png'); var canvasImg = $("<img id=canvasImg>"); canvasImg.attr('src', canvasUrl); canvasImg.appendTo("#render"); }, { crossOrigin: 'anonymous' });
内容的提问来源于stack exchange,提问作者TracyYXChen
相关产品推荐
相关产品推荐

