自定义组成要素:屏蔽范例

在设计使用 Blockly 的应用时,有几种范例可供选择。您应尽早考虑这些选择,因为它们会影响用户需要的块。

配置

许多 Blockly 应用用于描述配置,而不是可执行程序。配置应用通常首先初始化工作区上的一个根级块。Blockly 开发者工具的“Block Factory”标签页就是一个很好的例子:

Blockly.Blocks['factory_base'] = {
  init: function() {
    this.setDeletable(false);
    this.setMovable(false);
    this.setEditable(false);
    // etc...
  }
}

Blockly.serialization.blocks.append({'type': 'factory_base'}, workspace);

这样会创建一个不可删除、不可移动的块,用于保存用户的所有配置。您可以随时对工作区进行序列化,以确定当前配置。

此类应用可能希望自动停用未连接到根块的任何块。这可以通过一行代码来实现:

workspace.addChangeListener(Blockly.Events.disableOrphans);

序列号

大多数 Blockly 应用都旨在创建串行节目。用户将按顺序执行的代码块堆叠在一起。

工作区中的每个(未停用)块都将构成该计划的一部分。如果有多个堆栈的块,则会先执行较高的块。(如果两个堆栈的高度大致相同,则优先考虑靠左的堆栈(在 RTL 模式下)。)

工作区可以随时导出为可执行代码。此代码可以在客户端使用 JavaScript(使用 eval 或 JS 解释器)执行,也可以在服务器端以任何语言执行。

import {javascriptGenerator} from 'blockly/javascript';

var code = javascriptGenerator.workspaceToCode(workspace);

并行计划

某些 Blockly 应用选择并行(而非串行)执行所有块堆栈。例如,鼓循环与旋律并发运行的音乐应用。

实现并行执行的一种方法是分别为每个代码块生成代码:

import {javascriptGenerator} from 'blockly/javascript';

var json = Blockly.serialization.workspaces.save(workspace);

// Store top blocks separately, and remove them from the JSON.
var blocks = json['blocks']['blocks'];
var topBlocks = blocks.slice();  // Create shallow copy.
blocks.length = 0;

// Load each block into the workspace individually and generate code.
var allCode = [];
var headless = new Blockly.Workspace();
for (var i = 0; block < topBlocks.length; i++) {
  var block = topBlocks[i];
  blocks.push(block);
  Blockly.serialization.workspaces.load(json, headless);
  allCode.push(javascriptGenerator.workspaceToCode(headless));
  blocks.length = 0;
}

如果目标语言是 JavaScript,则 allCode 数组可用于创建多个 JS 解释器,以便同时执行。如果目标语言类似于 Python,则 allCode 数组可以组合成使用线程模块的单个程序。

与任何并行程序一样,您必须对任何共享资源(如变量和函数)做出谨慎的决策。

事件驱动型计划

事件处理脚本只是由系统(而不是程序)调用的函数。这些块可以封装要执行的块的堆栈,也可以是位于块堆栈顶部的标头。

有些开发者喜欢在事件块顶部添加“帽子”,使其看起来与其他块不同。这不是 Blockly 的默认外观,但可通过以下方法添加:将渲染程序常量 ADD_START_HATS 替换为 true自定义渲染程序 Codelab - 替换常量),或者添加主题并在块样式上设置 hat 选项。如需详细了解如何在主题中设置帽子,请点击此处

在事件驱动型模型中,可能还有必要为程序启动创建一个处理程序。在该模型中,工作区上未连接到事件处理脚本的任何块都将被忽略,并且不会执行。

在设计使用事件的系统时,请考虑是否可以支持或是否需要支持同一事件处理脚本的多个实例。