# 原生 JavaScript

> 不用框架，直接用 Fabric.js 原生 JavaScript：用事件或状态 store 连接撤销、重做和保存按钮。

Source: https://fabricjs-document-engine.jscrate.dev/zh/docs/frameworks/vanilla-js
Last updated: 2026-09-28

引擎的核心代码里没有任何框架相关的代码，所以 Fabric.js 原生 JavaScript 用起来和任何框架一样顺手。你创建画布、创建引擎，再根据它的状态更新工具栏。

## 页面

```html
<div role="toolbar">
  <button id="undo">Undo</button>
  <button id="redo">Redo</button>
  <button id="save">Save</button>
  <span id="status" aria-live="polite"></span>
</div>
<canvas id="editor"></canvas>
```

## 脚本

```ts
import { Canvas } from "fabric";
import {
  bindKeyboardShortcuts,
  createDocumentEngine,
  createDocumentStateStore,
} from "fabricjs-document-engine";
import { createLocalStorage } from "fabricjs-document-engine/storage";

const canvas = new Canvas("editor", { width: 800, height: 500 });
const engine = createDocumentEngine({
  canvas,
  storage: createLocalStorage(),
  autosave: true,
});
bindKeyboardShortcuts(engine);

const undo = document.querySelector<HTMLButtonElement>("#undo")!;
const redo = document.querySelector<HTMLButtonElement>("#redo")!;
const save = document.querySelector<HTMLButtonElement>("#save")!;
const status = document.querySelector("#status")!;

undo.addEventListener("click", () => engine.undo());
redo.addEventListener("click", () => engine.redo());
save.addEventListener("click", () => engine.save());

const store = createDocumentStateStore(engine);

function render() {
  const state = store.getSnapshot();
  undo.disabled = !state.canUndo;
  redo.disabled = !state.canRedo;
  save.disabled = !state.isDirty;
  status.textContent = state.saveStatus;
}

store.subscribe(render);
render();
```

`createDocumentStateStore` 提供一个快照，里面有工具栏需要的全部状态。它只在有订阅者时才监听引擎。

## 用事件代替 store

如果你只要一个值，监听单个事件就行：

```ts
engine.on("history:change", ({ canUndo, canRedo }) => {
  undo.disabled = !canUndo;
  redo.disabled = !canRedo;
});
```

`on` 会返回一个取消订阅的函数。完整列表见[事件](https://fabricjs-document-engine.jscrate.dev/zh/docs/api/events)。

## 不用打包工具

Fabric.js 原生 JavaScript 也可以借助 import map 直接从 CDN 加载。这个包以 ES 模块发布，不用框架也不用打包：

```html
<script type="importmap">
  {
    "imports": {
      "fabric": "https://cdn.jsdelivr.net/npm/fabric@7/+esm",
      "fabricjs-document-engine": "https://cdn.jsdelivr.net/npm/fabricjs-document-engine@1/+esm"
    }
  }
</script>
```

想一步步不用框架做出编辑器，请跟着[编辑器教程](https://fabricjs-document-engine.jscrate.dev/zh/docs/overview/tutorial)。
