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

Fabric.js自定义序列化问题:避免图片src序列化及解决对象丢失

解决Fabric.js自定义图片类序列化时移除src并正确反序列化的问题

我来帮你搞定这个问题——你遇到的核心问题是自定义fabric.Image子类的序列化/反序列化逻辑写得不对,尤其是fromObject方法的实现不符合Fabric.js的预期,再加上初始化方式的小错误,导致反序列化后对象丢失。下面是完整的解决方案:

问题分析

  1. 你之前的initialize方法参数不符合fabric.Image的规范:fabric.Image的构造函数第一个参数是图片元素(或canvas),第二个才是配置选项,你之前把options当成第一个参数传,导致图片实例没有正确初始化。
  2. fromObject方法误用了enlivenObjects:这个方法是用来处理包含子对象的复合元素(比如Group、Canvas)的,而你的MyImage是单个图片对象,完全不需要这个逻辑。
  3. 反序列化时没有根据自定义属性重新加载图片:你删除了src,但没有提供从自定义标识(比如entetyReference)重新获取图片源的逻辑,Fabric.js不知道怎么重建图片。

修正后的完整代码

1. 正确定义自定义图片类

fabric.MyImage = fabric.util.createClass(fabric.Image, {
  // 必须指定type,Fabric.js反序列化时靠这个识别类
  type: 'MyImage',

  /**
   * 初始化方法,遵循fabric.Image的参数规范
   * @param {HTMLImageElement|HTMLCanvasElement} element 图片元素
   * @param {Object} options 配置选项
   */
  initialize: function(element, options) {
    // 调用父类的初始化方法
    this.callSuper('initialize', element, options);
    // 初始化自定义属性
    this.set('entetyReference', options?.entetyReference || '');
    this.set('artIndexes', options?.artIndexes || '');
  },

  /**
   * 自定义序列化逻辑,只保留需要的属性
   * @param {string[]} propertiesToInclude 需要额外包含的属性
   */
  toObject: function(propertiesToInclude) {
    // 调用父类toObject,传入自定义属性列表,确保它们被序列化
    const baseObj = this.callSuper('toObject', [
      'entetyReference',
      'artIndexes',
      // 这里可以添加其他你需要序列化的自定义属性
    ]);
    // 删除不需要的src属性,减小序列化体积
    delete baseObj.src;
    return baseObj;
  }

  // 渲染逻辑直接继承父类即可,不需要重写,除非你有自定义渲染需求
  // _render: function(ctx) {
  //   this.callSuper('_render', ctx);
  // }
});

2. 实现正确的fromObject反序列化方法

这个方法的核心是根据你自定义的entetyReference重新获取图片源,然后创建MyImage实例:

/**
 * 从序列化对象重建MyImage实例
 * @param {Object} object 序列化后的对象
 * @param {Function} callback 回调函数,返回重建后的实例
 */
fabric.MyImage.fromObject = function(object, callback) {
  // 这里需要你自己实现:根据entetyReference获取对应的图片URL
  // 比如你可以维护一个映射表,或者通过接口获取
  const imageSource = getImageSourceByReference(object.entetyReference);

  // 使用Fabric.js内置的fromURL加载图片,然后创建MyImage实例
  fabric.Image.fromURL(imageSource, function(imgElement) {
    // 实例化MyImage,复制所有必要的属性(位置、缩放、旋转等)
    const myImage = new fabric.MyImage(imgElement, {
      entetyReference: object.entetyReference,
      artIndexes: object.artIndexes,
      // 复制Fabric.js内置的视觉属性,确保还原图片状态
      left: object.left,
      top: object.top,
      scaleX: object.scaleX,
      scaleY: object.scaleY,
      angle: object.angle,
      opacity: object.opacity,
      flipX: object.flipX,
      flipY: object.flipY,
      selectable: object.selectable
    });
    // 回调返回重建后的实例
    callback(myImage);
  });
};

// 标记该类的反序列化为异步(因为需要加载图片)
fabric.MyImage.async = true;

// 示例:根据entetyReference获取图片源的方法(你需要根据自己的业务实现)
function getImageSourceByReference(ref) {
  // 比如从映射表获取,或者拼接URL
  const imageMap = {
    'ref1': '/images/entity1.png',
    'ref2': '/images/entity2.png'
  };
  return imageMap[ref] || '/images/default.png';
}

3. 正确添加图片到Canvas

// 先通过Fabric.js加载图片元素,再创建MyImage实例
const entetyRef = 'ref1'; // 你的实体标识
const imageSource = getImageSourceByReference(entetyRef);

fabric.Image.fromURL(imageSource, function(imgElement) {
  const img = new fabric.MyImage(imgElement, {
    entetyReference: entetyRef,
    artIndexes: 'index-001' // 你的自定义索引
  });
  this.canvas.add(img);
}.bind(this)); // 确保this指向正确的上下文

使用序列化和反序列化

// 序列化Canvas(此时生成的JSON不会包含src,只保留自定义属性和必要的视觉属性)
const canvasJSON = this.canvas.toJSON();

// 反序列化Canvas
this.canvas.loadFromJSON(canvasJSON, function() {
  // 反序列化完成后重新渲染
  this.canvas.renderAll();
}.bind(this));

关键注意事项

  • 确保getImageSourceByReference方法能根据你的entetyReference正确返回图片URL,这是反序列化的核心。
  • 如果有其他自定义属性,记得在toObject的propertiesToInclude数组中添加,同时在fromObject中复制到新实例。
  • 所有Fabric.js内置的视觉属性(left、top、scaleX等)都要在fromObject中复制,否则反序列化后的图片状态会丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:18:22