向 Block Factory 添加插件字段

借助 Blockly 开发者工具,您可以使用块创建自定义块!除了核心 Blockly 附带的字段外,它还支持作为插件发布的字段。如果您已经创建了自定义字段,可以按照本指南向 Block Factory 添加对其的支持。必须在 npm 上发布自定义字段,然后才能添加对该字段的支持。您还需要致力于更新字段以适应 Blockly 中的更改,否则我们未来可能需要将其从 Block Factory 中移除。

在块工厂上进行开发

Block Factory 的源代码位于 examples/developer-tools 目录下的 blockly-samples 代码库中。

如需提交对块样本中的开发者工具所做的更改,您需要按照在块样本中进行开发的典型步骤进行操作。不过,与使用插件不同的是,您需要直接从 examples/developer-tools 目录(而不是在 blockly-samples 的根级别)运行 npm install

安装插件

为了让块工厂在预览中显示自定义字段,需要安装自定义字段。将您的字段添加为 developer-tools 的 npm 依赖项。然后注册它或在 developer-tools/src/blocks/index.ts 中执行任何其他必要的设置工作。

为该字段创建一个块

由于块工厂使用块来创建自定义块,因此您需要一个表示自定义字段的块。

创建屏蔽定义

您需要为自己的字段设计 block;如果您想获取 Meta,甚至可以使用 Block Factory 进行设计!该代码块应允许用户配置字段所需的设置,例如默认值和名称。将此块定义添加到 developer-tools/src/blocks/fields.ts,并将其导入 developer-tools/src/blocks/index.ts

向工具箱中添加数据块

接下来,您需要将此代码块添加到工具箱定义中,以供用户访问。工具箱定义位于 developer-tools/src/toolbox.ts 中。您应将屏蔽设置添加到“字段”类别中

代码生成器

Block Factory 使用您已熟悉的 Blockly 代码生成器系统来运行。对于块工厂生成的每类输出,每个块都有一个块码生成器,父块将子块的代码汇编到正确的输出中。若要添加对自定义字段的支持,您需要为每个代码生成器类添加区块码生成器函数。

output-generators/fields 目录中为字段块创建一个文件。您需要将以下每个生成器的块码生成器添加到此文件中。在 blocks/index.ts 文件中导入此文件,以便将区块码生成器函数加载到应用中。

JavaScript 定义

javascriptDefinitionGenerator 会为包含自定义字段的块创建将被添加到 JavaScript 定义中的代码。这通常意味着块码生成器应返回一行类似于 .appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName') 的代码。请注意,此代码行不包含分号,因为包含多个字段的输入将多次串联在一起对 appendField 的调用。构造函数中的参数是从用户在字段块上设置的值中提取的。以下是这个 FieldAngle 的块码生成器示例:

javascriptDefinitionGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: JavascriptDefinitionGenerator,
): string {
  const name = generator.quote_(block.getFieldValue('FIELDNAME'));
  const angle = block.getFieldValue('ANGLE');
  return `.appendField(new FieldAngle(${angle}), ${name})`;
};

用户从 Block Factory 工具箱的“Fields”类别中拖动的 angle 块有两个字段:

  • FIELDNAME:用户可以在自定义块中设置字段的名称
  • ANGLE:用户可以设置默认角度值

在此块码生成器中,我们会获取默认的 angle 值,并将其作为唯一参数传递给 FieldAngle 构造函数。字段名称始终会作为第二个参数传递给 appendField

JSON 定义

jsonDefinitionGenerator 与之类似,但这会输出 JSON 块定义中与字段相对应的部分。通常,此代码是一个包含以下内容的 JSON 对象:

  • type:对应于 Blockly 字段注册表中字段的名称
  • name:用户可以在自定义块中设置字段的名称
  • 字段的 json 初始化方法所需的任何其他自定义属性。

下面是 FieldAngle 中的示例:

jsonDefinitionGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: JsonDefinitionGenerator,
): string {
  const code = {
    type: 'field_angle',
    name: block.getFieldValue('FIELDNAME'),
    angle: block.getFieldValue('ANGLE'),
  };
  return JSON.stringify(code);
};

代码标头

代码标头生成器用于创建块工厂中显示的代码标头输出。此输出可以根据用户希望以何种方式加载代码,在 esmodule 导入和脚本标记之间切换,因此实际上存在两个不同的生成器实例:每种情况对应一个。您需要为每个图片添加区块码生成器。下面是一个 FieldAngle 示例:

importHeaderGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: CodeHeaderGenerator,
): string {
  generator.addHeaderLine(
    `import {registerFieldAngle, FieldAngle} from '@blockly/field-angle';`,
  );
  generator.addHeaderLine(`registerFieldAngle();`);
  return '';
};

scriptHeaderGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: CodeHeaderGenerator,
): string {
  generator.addHeaderLine(
    `<script src="https://unpkg.com/@blockly/field-angle"></script>`,
  );
  generator.addHeaderLine(`registerFieldAngle();`);
  return '';
};

这些生成器有一个名为 addHeaderLine 的方法,您可以通过该方法指定在将字段用于代码之前应调用的一行代码。通常,这包括导入字段或通过脚本标记加载字段,以及可能调用将使用 Blockly 的字段注册表注册字段的函数。

对于这两个块码生成器,应通过调用 addHeaderLine 添加所有代码。此函数可确保每个标头行仅显示一次,即使您在一个自定义块中多次使用了自定义字段块也是如此。块码生成器应返回空字符串。

生成器存根

最后,我们有为字段创建生成器存根的生成器。在此块码生成器中,您将编写可生成代码的代码,以帮助用户编写可生成代码的代码。还不清楚?听起来简单得多!

自定义块的生成器桩包含一个预创建的变量,用于表示块上的每个字段。然后是 TODO,用户必须完成将这些变量全部汇编到其自定义代码块返回的最终代码字符串中。这意味着,区块码生成器通常只需返回用于创建此自定义变量的代码行即可。假设用户正在制作一个自定义方块,用于向画布添加阳光光线。他们向该块添加了一个 angle 字段,并将其命名为 "SUN_DIRECTION"。此代码块的生成器桩将包含行 const angle_sun_direction = block.getFieldValue("SUN_DIRECTION");。以下是 angle 字段的块码生成器需要返回的代码块:

generatorStubGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: GeneratorStubGenerator,
): string {
  const name = block.getFieldValue('FIELDNAME');
  const fieldVar = generator.createVariableName('angle', name);
  return `const ${fieldVar} = block.getFieldValue(${generator.quote_(
    name,
  )});\n`;
};

如需获取变量的标准化名称,您可以调用 generator.createVariableName 并传入字段类型(例如 anglenumber 等)以及用户为其字段命名的名称。

测试应用

编写完以上所有部分后,您应该能够通过在 blockly-samples/examples/developer-tools 目录中运行 npm start 来启动块工厂。您应该能够从字段类别中拖动块,将其添加到块上的输入,然后观察输出的变化。请检查代码块的预览是否正确,以及每个输出部分的代码是否正确。