# 自定义对象

> 保存和加载 Fabric.js 自定义对象及其自定义属性。类注册一次即可，按 id 查找对象，避开 fromObject 报错。

Source: https://fabricjs-document-engine.jscrate.dev/zh/docs/guides/custom-objects
Last updated: 2026-09-28

Fabric.js 自定义对象是继承自 Fabric.js 类的类，通常带有额外的属性。普通的 `toJSON` 会丢掉这些属性，类不认识时加载还会失败。把类向引擎注册一次，这两个问题就都没了。

## 注册一个类

```ts
import { Rect } from "fabric";
import { createDocumentEngine } from "fabricjs-document-engine";

class Sticker extends Rect {
  static type = "Sticker";
  declare label: string;
}

const engine = createDocumentEngine({
  canvas,
  customObjects: [{ fabricClass: Sticker, properties: ["label"] }],
});
```

- 必须设置 `static type`，它就是保存在文档里的名字。
- `properties` 列出要保存和加载的自定义属性，不用每次保存都传。

也可以稍后注册，只要在加载需要这个类的文档之前即可：

```ts
engine.registerObject({ fabricClass: Sticker, properties: ["label"] });
```

## 未知类型会尽早失败

如果文档里有没注册的类型，加载会在动画布之前以 `UNKNOWN_OBJECT_TYPE` 失败。`error.unknownTypes` 会列出缺少的名字。对象不会被悄悄变成一个普通矩形。

这取代了普通 Fabric.js 在缺少类时那个让人摸不着头脑的 `klass.fromObject is not a function` 报错。引擎会把你的类注册到 Fabric.js，所以能找到它的 `fromObject`。

## 按对象 id 查找

每个对象都有稳定的 `id`，包括你的 Fabric.js 自定义对象和编组里的对象。用它把对象和你自己的数据关联起来：

```ts
const sticker = engine.getObjectById("a1b2c3");
sticker?.set("label", "Kitchen");
```

移动、编组、保存、撤销和重新打开之后，对象 id 都不变。撤销后请用 id 重新查找，因为实例已经是新的了。

## 项目数据放在 metadata 里

整份文档的数据，比如标题、所有者或标签，放在 `metadata` 里，而不是放在对象上：

```ts
engine.updateMetadata({ title: "Ground floor", owner: "user-42" });
```

## 两份 Fabric.js

如果打包结果里有两份 `fabric`，在一份里注册的类另一份不认识，Fabric.js 自定义对象就会以 `UNKNOWN_OBJECT_TYPE` 失败。请确认只安装了一份 `fabric`。详见[问题排查](https://fabricjs-document-engine.jscrate.dev/zh/docs/production/troubleshooting)。
