序列化

序列化是保存工作区的状态,以便稍后能够将其重新加载到工作区。这包括将要保存的任何代码块、变量或插件的状态序列化。您可以将需要保存的所有数据转换为基于文本的格式,以方便存储,然后在以后将这些数据加载回功能齐全的工作区。

Blockly 为这些数据提供了两种格式:JSON 和 XML。我们建议对新项目使用 JSON 系统,并鼓励使用 XML 升级的旧项目升级。XML 系统采用旧版保存格式。但不会移除,但不会收到新功能。

JSON 系统

JSON 序列化系统由多个序列化器组成。有一些适用于块和变量的内置序列化器,您也可以注册其他序列化器。每个序列化器负责对特定插件或系统的状态进行序列化和反序列化。

保存和加载

工作区

您可以通过对 workspaces 命名空间调用 saveload 方法,对整个工作区的状态进行序列化或反序列化。

const state = Blockly.serialization.workspaces.save(myWorkspace);
Blockly.serialization.workspaces.load(state, myWorkspace);

这些调用会序列化或反序列化在工作区中注册的所有系统(由序列化器表示)。

单个方块

您可以通过对 blocks 命名空间调用 saveappend 方法,对各个块进行序列化或反序列化。

const blockJson = Blockly.serialization.blocks.save(myBlock);
const duplicateBlock =
    Blockly.serialization.blocks.append(blockJson, myWorkspace);

个别系统

您可以通过构造关联的序列化器并调用其 saveload 方法,对各个系统(例如块、变量、插件等)进行序列化或反序列化。

// Saves only the variables information for the workspace.
const serializer = new Blockly.serialization.variables.VariableSerializer();
const state = serializer.save(myWorkspace);
serializer.load(state, myWorkspace);

反序列化顺序

JSON 系统具有明确的反序列化顺序,因此可以更轻松地防止在保存过程中出现重复状态。

调用 Blockly.serialization.workspaces.load 时,系统会按优先级为序列化器指定反序列化状态。序列化器部分对此进行了进一步说明,其用途是允许序列化器依赖于来自其他系统的状态。

内置序列化器的反序列化顺序如下:

  1. 变量是反序列化的。
  2. 代码块会反序列化。各个堆栈/顶级块按任意顺序反序列化。
    1. 类型反序列化。这会触发块的 init 方法、扩展程序中的混音,等等。
    2. 属性反序列化。这包括可应用于任何块的属性。例如:x、y、合拢、已停用、数据等。
    3. Extra 状态会进行反序列化。如需了解详情,请参阅扩展程序和变更器文档。
    4. 代码块会连接到其父级组件(如果存在)。
    5. 图标是反序列化的。各个图标按任意顺序反序列化。
    6. 字段会反序列化。各个字段以任意顺序进行反序列化。
    7. 输入块反序列化。这包括连接到值输入和语句输入的块。各个输入按任意顺序进行反序列化。
    8. 后续代码块会反序列化。

何时保存额外状态

对于块,如果顺序中较低部分依赖于顺序中的较高部分,则应复制相应数据并将其添加到额外状态。

例如,如果您有一个字段仅在下一个块连接的情况下存在,则应该将有关下一个块的信息添加到额外状态,以便在将字段状态反序列化之前,可以将该字段添加到您的块中。

但是,如果输入仅在某个字段具有特定值时存在,则无需向额外状态添加有关该字段的信息。这是因为字段状态将首先进行反序列化,届时,您可以将输入添加到块中。添加输入通常由验证器触发。

请注意,有关复制状态的规则还应考虑屏蔽堆栈、图标、字段和输入块按任意顺序反序列化。例如,有一个字段 B 仅在另一个字段 A 具有特定值时存在,您应将 A 的相关信息添加到额外状态,以防 B 在 A 之前反序列化。

块钩子

如需了解如何向块中添加额外的序列化,请参阅扩展和变更器文档。

字段钩子

如需了解如何对字段进行序列化,请参阅自定义字段文档。

序列化器钩子

在 JSON 系统中,您可以注册序列化器,这些序列化器用于对某些状态进行序列化和反序列化。Blockly 的内置序列化器负责序列化有关块和变量的信息,但如果您想序列化其他信息,则需要添加自己的序列化器。例如,默认情况下,JSON 系统不会序列化工作区级注释。如果要将其序列化,您需要注册额外的序列化器。

其他序列化器通常用于对插件的状态进行序列化和反序列化。

Blockly.serialization.registry.register(
    'workspace-comments',  // Name
    {
      save: saveFn,      // Save function
      load: loadFn,      // Load function
      clear: clearFn,    // Clear function
      priority: 10,      // Priority
    });

注册序列化器时,您必须提供以下各项:

  • 序列化器的名称,数据也会保存在其中。
  • 一个函数,用于save与序列化器关联的插件/系统的状态。
  • 用于对状态执行 clear 的函数。
  • 用于对状态执行 load 的函数。
  • priority,用于确定反序列化顺序

    序列化器的优先级基于内置优先级

调用 Blockly.serialization.workspaces.save 时,系统会调用每个序列化器的 save 函数,并将其数据添加到最终 JSON 输出中:

{
  "blocks": { ... },
  "workspaceComments": [ // Provided by workspace-comments serializer
    {
      "x": 239,
      "y": 31,
      "text": "Add 2 + 2"
    },
    // etc...
  ]
}

调用 Blockly.serialization.workspaces.load 时,每个序列化器都会按优先级触发。优先级值较高的序列化器会在优先级值较低的序列化器之前触发。

触发序列化器时,会出现以下两种情况:

  1. 系统会调用所提供的 clear 函数。这样可以确保在加载更多状态之前,插件/系统的状态是干净的。例如,workspace-comments 序列化器会从工作区中移除所有现有注释。
  2. 系统会调用所提供的 load 函数。

XML 系统

利用 XML 系统,您可以将工作区序列化为 XML 节点。这是 Blockly 的原始序列化系统。它现在已采用冰箱模式,这意味着它不会接收新功能。因此,建议您尽可能使用 JSON 系统。

API

如需了解 XML 系统的 API,请参阅参考文档

块钩子

如需了解如何向块中添加额外的序列化,请参阅扩展和变更器文档。

字段钩子

如需了解如何对字段进行序列化,请参阅自定义字段文档。

选择 JSON 或 XML

我们建议您使用 JSON 序列化器而非 XML 序列化器。通过 JSON 系统,您可以将工作区的状态序列化为 JavaScript 对象。这样做的好处在于:

  1. JSON 易于压缩或转换为其他格式。
  2. 以编程方式使用 JSON 非常容易。
  3. JSON 可以轻松扩展和附加数据。

此外,XML 系统将不再接收更新,并且与 JSON 序列化器相比,已经缺少功能。例如,您可以注册自己的 JSON 序列化器,以便轻松保存和加载其他数据,例如您已添加的插件或自定义项的数据。在 XML 系统中不可能做到这一点。

如果您之前使用过 XML 序列化,请参阅迁移指南,了解如何升级。