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

Fabric JS 5.3.0自定义类无法序列化,触发TypeError报错

解决Fabric JS 5.3.0自定义类序列化问题

报错原因

你尝试设置fabric.labeledRect.fromObject时触发报错,核心原因有两点:

  1. 自定义的LabeledRect类仅作为局部变量存在,未注册到Fabric全局命名空间,导致fabric.labeledRect不存在;
  2. Fabric内置类均采用大驼峰命名(如fabric.Rect),你误用了小写的labeledRect,不符合框架命名规范。

修正步骤

1. 注册自定义类到Fabric全局命名空间

在定义完LabeledRect类后,将其挂载到fabric对象,确保框架能识别该类:

fabric.LabeledRect = LabeledRect;

2. 正确实现fromObject静态方法

Fabric 5.x中,需将fromObject添加到已注册的类上,同时修正_fromObject的调用参数(传入正确的类引用):

fabric.LabeledRect.fromObject = function(object, callback) {
  return fabric.Object._fromObject(fabric.LabeledRect, object, callback);
};

也可以在类定义时直接通过静态属性添加,更简洁:

var LabeledRect = fabric.util.createClass(fabric.Rect, {
  // 原有类属性和方法
}, {
  // 静态方法
  fromObject: function(object, callback) {
    return fabric.Object._fromObject(LabeledRect, object, callback);
  }
});

3. 补充初始化默认属性

你的_render方法使用了this.labelFont和this.labelFill,但初始化时未设置默认值会导致渲染错误,需在initialize中补充:

initialize: function(options) {
  options || (options = {});
  this.callSuper('initialize', options);
  this.set({ width: 100, height: 50 });
  // 添加字体、颜色默认值
  this.set('labelFont', options.labelFont || '14px Arial');
  this.set('labelFill', options.labelFill || '#000');
  this.set('label', options.label || '');
}

4. 调整序列化/反序列化顺序

确保fromObject方法在序列化(JSON.stringify(canvas))之前定义,否则Fabric无法识别自定义类的序列化格式。

完整修正代码

var canvas = new fabric.Canvas("myCanvas");

canvas.setWidth(window.innerWidth);
canvas.setHeight(window.innerHeight);

window.addEventListener("resize", function () {
  canvas.setWidth(window.innerWidth);
  canvas.setHeight(window.innerHeight);
});

// 定义自定义类
var LabeledRect = fabric.util.createClass(fabric.Rect, {
  type: 'labeledRect',

  initialize: function(options) {
    options || (options = {});
    this.callSuper('initialize', options);
    this.set({ width: 100, height: 50 });
    // 设置默认属性
    this.set('labelFont', options.labelFont || '14px Arial');
    this.set('labelFill', options.labelFill || '#000');
    this.set('label', options.label || '');
  },

  toObject: function () {
    return fabric.util.object.extend(this.callSuper('toObject'), {
      label: this.get('label'),
      labelFont: this.get('labelFont'),
      labelFill: this.get('labelFill')
    });
  },

  _render: function(ctx) {
    // 先调用父类方法绘制基础矩形
    this.callSuper('_render', ctx);
    ctx.font = this.labelFont;
    ctx.fillStyle = this.labelFill;
    ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
  }
}, {
  // 静态fromObject方法
  fromObject: function(object, callback) {
    return fabric.Object._fromObject(LabeledRect, object, callback);
  }
});

// 注册到Fabric全局命名空间
fabric.LabeledRect = LabeledRect;

// 创建实例并添加到画布
var labeledRect = new LabeledRect({
  width: 100,
  height: 50,
  left: 100,
  top: 100,
  label: 'test',
  fill: '#faa'
});
canvas.add(labeledRect);

// 序列化与反序列化
var savedJson = JSON.stringify(canvas.toJSON());
console.log(savedJson);
canvas.loadFromJSON(savedJson, function() {
  canvas.renderAll();
});

额外说明

  • 使用canvas.toJSON()代替直接JSON.stringify(canvas),这是Fabric推荐的序列化方式,能更准确导出画布数据;
  • 在loadFromJSON的回调中执行renderAll(),确保反序列化完成后再重新渲染画布;
  • _render方法中先调用this.callSuper('_render', ctx)绘制基础矩形,再绘制文本,避免覆盖父类的渲染逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:15:37