定义块
块定义描述了块的外观和行为,包括文本,颜色,形状以及它可以连接的其他块。
定义自定义块后,每个平台都会以不同的方式加载这些定义,详细信息请参见 网络和 Android特定配置指南。
JSON格式与JavaScript API
Blockly有两种定义块的方式:JSON对象和JavaScript函数。JSON格式是跨平台的,因此可以使用相同的代码在Web,Android和iOS上定义块。此外,JSON格式旨在在开发具有不同单词顺序的语言时简化本地化过程。JSON格式是定义块的首选方法。
但是,JSON格式无法直接定义高级功能,例如变异器或验证器。这些必须以平台的本机代码,JavaScript,Java或Swift编写,通常作为 扩展。
使用Blockly的原始JavaScript实现的应用程序也可以直接将块定义写入较低级别的Blockly API函数调用,如下面的各种JavaScript示例所示。
//javascript
Blockly.Blocks['string_length'] = {
init: function() {
this.appendValueInput('VALUE')
.setCheck('String')
.appendField('length of');
this.setOutput(true, 'Number');
this.setColour(160);
this.setTooltip('Returns number of letters in the provided text.');
this.setHelpUrl('http://www.w3schools.com/jsref/jsref_length_string.asp');
}
};
//json
{
"type": "string_length",
"message0": 'length of %1',
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": "String"
}
],
"output": "Number",
"colour": 160,
"tooltip": "Returns number of letters in the provided text.",
"helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp"
}
两个示例均加载相同的“ string_length”块。
在Web上,使用initJson
函数加载JSON格式。这也允许将两种格式混合在Blockly网页中。最好在可能的情况下使用JSON定义您的块,并且仅将JavaScript用于JSON不支持的部分块定义。
以下是一个块的示例,该块主要使用JSON定义,但使用JavaScript API进行了扩展,以提供动态工具提示。
var mathChangeJson = {
"message0": "change %1 by %2",
"args0": [
{"type": "field_variable", "name": "VAR", "variable": "item", "variableTypes": [""]},
{"type": "input_value", "name": "DELTA", "check": "Number"}
],
"previousStatement": null,
"nextStatement": null,
"colour": 230
};
Blockly.Blocks['math_change'] = {
init: function() {
this.jsonInit(mathChangeJson);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function() {
return 'Add a number to variable "%1".'.replace('%1',
thisBlock.getFieldValue('VAR'));
});
}
};
Block colour
块的主颜色由JSON colour属性block.setColour(..)函数定义,或者通过使用主题和定义块样式来定义。
//JSON
{
// ...,
"colour": 160,
}
//javascript
init: function() {
// ...
this.setColour(160);
}
有关详细信息,请参阅块颜色指南。
Statement Connections (块连接)
用户可以使用nextStatement和previousStatement连接器创建块序列。在Blockly的标准布局中,这些连接位于顶部和底部,块垂直堆叠。
带有前一个连接器的块不能有输出连接器,反之亦然。语句块是指没有值输出的块。语句块通常同时具有前一个连接和下一个连接。
可以键入nextStatement和previousStatement连接,但标准块不使用此功能。
Next Connection (向下连接)
在块的底部创建一个点,以便其他语句可以堆叠在它的下面。具有下一个连接但没有上一个连接的块通常表示一个事件,并且可以配置为使用hat呈现。
// JSON
Untyped:
{
...,
"nextStatement": null,
}
Typed (rare):
{
"nextStatement": "Action",
...
}
//javascript
Untyped:
this.setNextStatement(true); // false implies no next connector, the default
Typed (rare):
this.setNextStatement(true, 'Action');
Previous Connection (向上连接)
在块的顶部创建槽口,以便它可以作为语句堆栈连接。
具有先前连接的块不能有输出连接。
//JSON
Untyped:
{
...,
"previousStatement": null,
}
Typed (rare):
{
"previousStatement": "Action",
...
}
//javascript
Untyped:
this.setPreviousStatement(true); // false implies no previous connector, the default
Typed (rare):
this.setPreviousStatement(true, 'Action');
Block Output (块输出)
块可以具有单个输出,表示为前缘上的公拼图连接器。输出连接到值输入。具有输出的块通常称为值块。
//JSON
Untyped:
{
// ...,
"output": null,
}
Typed:
{
// ...,
"output": "Number",
}
//javascript
Untyped:
init: function() {
// ...
this.setOutput(true);
}
Typed:
init: function() {
// ...
this.setOutput(true, 'Number');
}
带有输出连接器的块也不能有前一个语句槽。
Block Inputs
一个块有一个或多个输入,其中每个输入是可能以连接结束的标签和字段序列。有三种输入类型,与连接类型匹配:
Value input:连接到值块的输出连接。math_算术块(加法、减法)是具有两个值输入的块的示例。
Statement input:连接到语句块的前一个连接。while循环的嵌套部分是语句输入的一个示例。
Dummy input:没有块连接。当块被配置为使用外部值输入时,其行为类似于换行符。
JSON格式和JavaScript API使用稍微不同的模型来描述它们的输入。
Inputs and Fields in JSON
JSON定义的块被构造为一个插值消息字符串序列(message0、message1,…),其中每个插值标记(%1、%2,…)是匹配的JSON argsN数组中的字段或输入端(因此,在消息中输入连接器呈现)。这种格式旨在使国际化变得容易。
{
"message0": "set %1 to %2",
"args0": [
{
"type": "field_variable",
"name": "VAR",
"variable": "item",
"variableTypes": [""]
},
{
"type": "input_value",
"name": "VALUE"
}
]
}
插值标记必须与args0数组完全匹配:无重复,无遗漏。标记可以以任何顺序出现,这允许不同的语言更改块的布局。
插值标记两边的文本将被空格修剪。使用字符的文本(例如,当引用百分比时)应使用%%,这样它就不会被解释为插值标记。
参数的顺序和参数类型定义块的形状。更改其中一个字符串可以完全更改块的布局。这在语序与英语不同的语言中尤为重要。假设有一种语言,其中“set%1 to%2”(如上面的例子中所使用的)需要颠倒过来,表示“put%2 in%1”。更改这一个字符串(并保持JSON的其余部分不变)将导致以下块:
块自动改变字段的顺序,创建一个虚拟输入,并从外部输入切换到内部输入。
Args
每个消息字符串都与一个相同编号的args数组配对。例如,message0
与args0一起使用。插值标记(%1、%2,…)引用args数组的项。每个对象都有一个类型字符串。其余参数因类型而异:
每个对象也可能有alt字段。如果Blockly无法识别对象的类型,则使用alt对象代替它。例如,如果将名为field_time的新字段添加到Blockly,则使用此字段的块可以使用alt为Blockly的旧版本定义field_input fallback:
{
"message0": "sound alarm at %1",
"args0": [
{
"type": "field_time",
"name": "TEMPO",
"hour": 9,
"minutes": 0,
"alt":
{
"type": "field_input",
"name": "TEMPOTEXT",
"text": "9:00"
}
}
]
}
alt对象可能有自己的alt对象,因此允许链接。最后,如果Blockly无法在args0数组中创建对象(在尝试任何alt对象之后),则只跳过该对象。
如果消息字符串以不包含在输入中的文本或字段结尾,则将自动在块的末尾添加一个伪输入。因此,如果块上的最后一个输入是伪输入,则可以从args数组中省略它,并且不需要在消息中插入。自动添加拖尾伪输入允许转换器更改消息,而无需修改JSON的其余部分。请参阅本页前面的“将%1设置为%2”(无伪输入)和“将%2放入%1”(添加了伪输入)示例。
lastDummyAlign0
在极少数情况下,自动创建的尾部伪输入需要与“右”或“中心”对齐。如果未指定,则默认值为“左”。
在下面的示例中,message0
is "send email to %1 subject %2 secure %3"
,并为第三行自动添加一个虚拟输入。将lastDummyAlign0设置为“RIGHT”将强制此行右对齐。
在为RTL(阿拉伯语和希伯来语)设计块时,左右颠倒。因此,“RIGHT”将字段与左边对齐。
message1
, args1
, lastDummyAlign1
有些区块自然分成两个或多个独立的部分。考虑这个重复块,它有两行:
如果用单个消息描述此块,则message0属性将为“repeat %1次%2执行%3”。这个字符串对于翻译来说很难理解,很难解释%2替换意味着什么。在某些语言中甚至可能不需要%2伪输入。可能有多个块希望共享第二行的文本。一种更好的方法是JSON使用多个消息和args属性:
{
"type": "controls_repeat_ext",
"message0": "repeat %1 times",
"args0": [
{"type": "input_value", "name": "TIMES", "check": "Number"}
],
"message1": "do %1",
"args1": [
{"type": "input_statement", "name": "DO"}
],
"previousStatement": null,
"nextStatement": null,
"colour": 120
}
任何数量的消息、参数和lastDummyAlign属性都可以用JSON格式定义,从0开始并按顺序递增。请注意,块工厂不能将消息拆分为多个部分,但手动执行此操作非常简单。
Inputs and Fields in JavaScript
JavaScript API为每个输入类型都包含一个append方法:
this.appendDummyInput()
.appendField('for each')
.appendField('item')
.appendField(new Blockly.FieldVariable());
this.appendValueInput('LIST')
.setCheck('Array')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField('in list');
this.appendStatementInput('DO')
.appendField('do');
每个方法都可以采用由代码生成器使用的标识符字符串。虚拟输入很少需要引用,标识符通常不设置。
如上所示,每个方法都通过方法链返回要配置的输入对象。有三个功能用于配置输入。
setCheck
input.setCheck('Number');
此可选功能用于连接输入的类型检查。如果给定的参数为null(默认值),则此输入可以连接到任何块。有关详细信息,请参见类型检查。
setAlign
input.setAlign(Blockly.ALIGN_RIGHT);
此可选功能用于对齐字段(请参见下文)。有三个自描述性值可以作为参数传递给此函数:Blockly.ALIGN_LEFT、Blockly.ALIGN_RIGHT和Blockly.ALIGN_CENTRE。注意“center”的英国拼写。默认为左对齐。
在为RTL(阿拉伯语和希伯来语)设计块时,左右颠倒。因此Blockly.ALIGN_RIGHT会将字段左对齐。
appendField
一旦创建了输入并将其附加到带有append input的块中,就可以选择将任意数量的字段附加到输入中。这些字段通常用作描述每个输入的用途的标签。
input.appendField('hello');
最简单的字段元素是文本。Blockly的惯例是使用所有小写文本,但专有名称除外(例如Google、SQL)。
输入行可以包含任意数量的字段元素。可以将多个appendField调用链接在一起,以便有效地将多个字段添加到同一输入行。
input.appendField('hello')
.appendField(new Blockly.FieldLabel('Neil', 'person'));
appendField('hello')调用实际上是使用显式FieldLabel构造函数的快捷方式:appendField(new Blockly.FieldLabel('hello'))。只有在指定类名时才希望使用构造函数,以便可以使用CSS规则对文本进行样式设置。
Inline vs. External
块输入可以呈现为外部或内部。
块定义可以指定可选的布尔值,以控制输入是否内联。如果为false,则任何值输入都将是外部的(例如左块)。如果为true,则任何值输入都将内联(如上面的右块)。
//json
{
// ...,
"inputsInline": true
}
//javascript
init: function() {
// ...
this.setInputsInline(true);
}
如果没有定义,那么Blockly将使用一些启发式方法来猜测哪种模式是最好的。假设Blockly做出了正确的选择,最好不定义这个字段,因为不同的语言翻译可以自动具有不同的模式。请参阅本页前面的JSON示例“将%1设置为%2”(外部输入)和“将%2放入%1”(内联输入)。
当块可能有小的输入(如数字)时,使用内联输入。如果启用折叠配置(如果工具箱具有类别,则默认为true),则用户可以通过上下文菜单切换此选项。
Fields
字段定义块中的UI元素。其中包括字符串标签、图像和文本数据(如字符串和数字)的输入。最简单的例子是math_number块,可以是field_input(web)或field_number(Android)来输入数字。
Blockly提供了许多内置字段,包括文本输入、颜色选择器和图像。也可以创建自己的字段。
有关 built-in fields.的更多信息。
有关creating custom fields.的详细信息。
Tooltips
当用户将鼠标悬停在块上时,工具提示提供即时帮助。如果文本很长,它将自动换行。
//json
{
// ...,
"tooltip": "Tooltip text."
}
//javascript
init: function() {
this.setTooltip("Tooltip text.");
}
在JavaScript API中,工具提示也可以定义为函数而不是静态字符串。这允许动态帮助。有关工具提示的示例,请参见math_算术,该工具提示会根据选择的下拉选项而更改。
Blockly.Blocks['math_arithmetic'] = {
init: function() {
// ...
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function() {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
};
return TOOLTIPS[mode];
});
}
};
使用JavaScript API,块可以指定一个函数,而不是返回工具提示字符串的静态字符串。这允许动态工具提示。例如,参见数学。
Help URL
块可以具有与其关联的帮助页。Blockly for Web的用户可以通过右键单击该块并从上下文菜单中选择“帮助”来使用它。如果此值为空,则菜单将灰显。
//JSON
{
// ...,
"helpUrl": "https://en.wikipedia.org/wiki/For_loop"
}
//javascript
init: function() {
// ...
this.setHelpUrl('https://en.wikipedia.org/wiki/For_loop');
}
使用JavaScript API,块可以指定一个函数,而不是返回URL字符串的静态字符串,从而允许动态帮助。
Change Listeners and Validators
块可以具有对工作区的任何更改(包括与块无关的更改)调用的更改侦听器函数。它们主要用于设置块的警告文本或工作区外的类似用户通知。
通过使用函数调用setOnChange来添加该函数,如果计划在所有平台上使用它,则可以在init期间或通过JSON扩展来完成。
//JSON
{
// ...,
"extensions":["warning_on_change"],
}
Blockly.Extensions.register('warning_on_change', function() {
// Example validation upon block change:
this.setOnChange(function(changeEvent) {
if (this.getInput('NUM').connection.targetBlock()) {
this.setWarningText(null);
} else {
this.setWarningText('Must have an input block.');
}
});
});
//javascript
Blockly.Blocks['block_type'] = {
init: function() {
// Example validation upon block change:
this.setOnChange(function(changeEvent) {
if (this.getInput('NUM').connection.targetBlock()) {
this.setWarningText(null);
} else {
this.setWarningText('Must have an input block.');
}
});
}
}
系统调用函数,传递change事件。在函数内部,这指的是块实例。
因为函数是在任何更改时调用的,如果使用,开发人员应该确保监听器快速运行。还应该注意对工作区的更改,这些更改可能会层叠或循环回侦听器。
有关示例,请参阅controls_flow_statements、logic_compare和procedures_ifreturn块。
请注意,可编辑字段有自己的事件侦听器,用于输入验证并产生副作用。
Mutator
变异器允许高级块更改形状,特别是当用户打开一个对话框来添加、删除或重新排列组件时。可以使用mutator键通过JSON添加mutator。
{
// ...,
"mutator":"if_else_mutator"
}
Per-block configuration
块实例具有许多属性,可配置它们对用户的行为方式。它们可以用来约束工作区以反映域的某些属性(例如,只有一个“开始”事件),或者集中用户的精力(例如,教程)。
Deletable State
默认情况下,用户可以删除可编辑工作区(而不是只读)上的任何块。有时,使某些块成为永久性固定装置是有用的。例如,教程框架代码。
block.setDeletable(false);
任何块,包括那些标记为不可删除的块,都可以通过编程方式删除:
block.dispose();
Editable State
block.setEditable(false);
当设置为false时,用户将无法更改块的字段(例如下拉列表和文本输入)。块在可编辑工作空间上默认为可编辑。
Movable State
block.setMovable(false);
当设置为false时,用户将无法直接移动块。作为另一个块的子块的不可移动块不能从该块断开,尽管如果父块被移动,它将与其父块一起移动。
块默认为在可编辑工作空间上可移动。
任何块(甚至是不可移动的块)一旦在工作区上,就可以通过编程方式移动。在JavaScript中,调用block.moveBy(dx,dy)。除非另有指定,否则工作区上块的起始位置默认为(0,0)。
Block data (web only)
this.data = '16dcb3a4-bd39-11e4-8dfc-aa07a5b093db'; // Web only
数据是附加到块的可选任意字符串。当保存为XML时,数据字符串存储在一个<data></data>标记中,以便它可以往返返回到一个块。使用数据字符串将块与外部资源关联或用于任何其他自定义目的。
请注意,如果块被复制或复制/粘贴,则数据字符串也会被复制。无法复制或复制/粘贴不可删除的块。