扩展是在给定类型的每个块上运行的函数,因为块是 创建。这类操作通常会将一些自定义配置或行为添加到代码块中。
赋值函数是一种特殊的扩展程序,可添加自定义序列化,并且 通常是 UI 的
扩展程序
扩展是在给定类型的每个块上运行的函数,因为块是 创建。他们可添加自定义配置(例如设置屏蔽的提示)或 自定义行为(例如,向代码块添加事件监听器)。
// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
'parent_tooltip_extension',
function() { // this refers to the block that the extension is being run on
var thisBlock = this;
this.setTooltip(function() {
var parent = thisBlock.getParent();
return (parent && parent.getInputsInline() && parent.tooltip) ||
Blockly.Msg.MATH_NUMBER_TOOLTIP;
});
});
扩展程序必须“注册”以便将其与字符串相关联
键。然后,您可以将此字符串键分配给您的extensions
属性
块类型的 JSON
定义以将
扩展。
{
//...,
"extensions": ["parent_tooltip_extension",]
}
您也可以一次添加多条附加信息。请注意,extensions
属性必须是数组,即使您只应用一个扩展也是如此。
{
//...,
"extensions": ["parent_tooltip_extension", "break_warning_extension"],
}
合辑
此外,Blockly 还提供了一种便捷的方法,供您在需要添加 将一些属性/辅助函数添加到块中,但不要立即运行它们。这个 方法是在 Google Cloud 中注册一个mixin 对象,其中包含所有其他属性/方法。Mixin 对象 然后,该函数被封装在一个函数中,该函数会在每次 系统就会创建指定的屏蔽类型
Blockly.Extensions.registerMixin('my_mixin', {
someProperty: 'a cool value',
someMethod: function() {
// Do something cool!
}
))`
可以在 JSON 中引用与 mixins 关联的字符串键,就像引用任何其他项一样 。
{
//...,
"extensions": ["my_mixin"],
}
变更器
赋值函数是一种特殊类型的扩展程序,它会添加额外的序列化(额外
保存和加载的状态)。例如,内置的
controls_if
和 list_create_with
块需要额外的序列化,以便
就可以节省自己拥有的输入量。
请注意,更改砌块的形状并不一定意味着您需要
额外的序列化。例如,math_number_property
代码块会更改为
但它基于一个下拉菜单字段执行该操作,该字段的值已有
序列化。因此,只需使用字段
验证程序
需要一个赋值函数。
有关详情,请参阅序列化 页 。
Mutator 还提供内置界面,以便用户在发生以下情况时更改方块的形状: 您需要提供一些可选方法。
序列化钩子
变更器有两对与之搭配使用的序列化钩子。一对钩子 适用于新的 JSON 序列化系统,而另一对适用于 旧 XML 序列化系统。您必须至少提供这些键值对中的一个。
SaveExtraState 和 loadExtraState
saveExtraState
和 loadExtraState
是与
新的 JSON 序列化系统。saveExtraState
会返回可序列化的 JSON
值(表示块的额外状态),以及 loadExtraState
接受相同的 JSON 可序列化值,并将其应用于块。
// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
return {
'itemCount': this.itemCount_,
};
},
loadExtraState: function(state) {
this.itemCount_ = state['itemCount'];
// This is a helper function which adds or removes inputs from the block.
this.updateShape_();
},
生成的 JSON 将如下所示:
{
"type": "lists_create_with",
"extraState": {
"itemCount": 3 // or whatever the count is
}
}
无状态
如果您的代码块在序列化时处于默认状态,那么
saveExtraState
方法可以返回 null
来指明这一点。如果您的
saveExtraState
方法返回 null
,但不向其中添加任何 extraState
属性
JSON。这样可以使保存的文件保持小巧。
完整的序列化和后备数据
saveExtraState
还会接收可选的 doFullSerialization
参数。这个
由引用状态(由另一个
序列化器(如支持数据模型)。参数表示
在块被反序列化时,引用的状态将不可用,因此
应将所有后备状态本身序列化。例如,
在序列化单个块或复制粘贴块时为 true。
这有两个常见用例:
- 当单个块被加载到后备数据的工作区时 模型不存在,但它拥有足够的信息, 创建新的数据模型。
- 复制粘贴文本块时,它始终会创建新的后备内容 而不是引用现有模型。
一些使用该参数的区块包括
@blockly/block-shareable-procedures 代码块。正常
它们将对存储其状态的后备数据模型的引用序列化。
但是,如果 doFullSerialization
参数为 true,它们会序列化所有
状态可共享的过程块使用此机制来确保
它们会创建新的后备数据模型,而不是引用
现有模型。
mutateToDom 和 domToMutation
mutationToDom
和 domToMutation
是与
旧 XML 序列化系统。除非必要(例如
处理尚未迁移的旧代码库),否则请使用
saveExtraState
和loadExtraState
。
mutationToDom
会返回一个 XML 节点,该节点表示
块,domToMutation
接受相同的 XML 节点,并将状态应用于
。
// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
// You *must* create a <mutation></mutation> element.
// This element can have children.
var container = Blockly.utils.xml.createElement('mutation');
container.setAttribute('items', this.itemCount_);
return container;
},
domToMutation: function(xmlElement) {
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
// This is a helper function which adds or removes inputs from the block.
this.updateShape_();
},
生成的 XML 应如下所示:
<block type="lists_create_with">
<mutation items="3"></mutation>
</block>
如果 mutationToDom
函数返回 null,则不会出现任何额外的元素
添加到 XML 中
界面钩子
如果您提供某些功能作为赋值函数的一部分,Blockly 会添加一个 默认的“更改器”添加到区块中的界面
如果您想添加额外的序列化,则无需使用此界面。您可以 使用自定义界面,例如 blocks-plus---minus 插件 否则,您根本不需要使用界面!
编写和分解
默认界面依赖于 compose
和 decompose
函数。
decompose
“爆炸”将文本块拆分成更小的子块
已添加和删除的信息此函数应返回一个“顶部代码块”也就是
子块连接到的赋值函数工作区中的主块。
然后,compose
会解释子块的配置,并将其用于
修改 main 代码块。此函数应接受“top block”也就是
作为参数由 decompose
返回。
请注意,这些函数会“混合”被修改的块所以this
都可用于引用该代码块
// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
// This is a special sub-block that only gets created in the mutator UI.
// It acts as our "top block"
var topBlock = workspace.newBlock('lists_create_with_container');
topBlock.initSvg();
// Then we add one sub-block for each item in the list.
var connection = topBlock.getInput('STACK').connection;
for (var i = 0; i < this.itemCount_; i++) {
var itemBlock = workspace.newBlock('lists_create_with_item');
itemBlock.initSvg();
connection.connect(itemBlock.previousConnection);
connection = itemBlock.nextConnection;
}
// And finally we have to return the top-block.
return topBlock;
},
// The container block is the top-block returned by decompose.
compose: function(topBlock) {
// First we get the first sub-block (which represents an input on our main block).
var itemBlock = topBlock.getInputTargetBlock('STACK');
// Then we collect up all of the connections of on our main block that are
// referenced by our sub-blocks.
// This relates to the saveConnections hook (explained below).
var connections = [];
while (itemBlock && !itemBlock.isInsertionMarker()) { // Ignore insertion markers!
connections.push(itemBlock.valueConnection_);
itemBlock = itemBlock.nextConnection &&
itemBlock.nextConnection.targetBlock();
}
// Then we disconnect any children where the sub-block associated with that
// child has been deleted/removed from the stack.
for (var i = 0; i < this.itemCount_; i++) {
var connection = this.getInput('ADD' + i).connection.targetConnection;
if (connection && connections.indexOf(connection) == -1) {
connection.disconnect();
}
}
// Then we update the shape of our block (removing or adding iputs as necessary).
// `this` refers to the main block.
this.itemCount_ = connections.length;
this.updateShape_();
// And finally we reconnect any child blocks.
for (var i = 0; i < this.itemCount_; i++) {
connections[i].reconnect(this, 'ADD' + i);
}
},
saveConnections
您还可以选择定义一个 saveConnections
函数,
默认界面此函数让您有机会将
主块(位于主工作区中)和位于主工作区中的子块
来进行更改。然后,您可以使用此数据来确保您的compose
功能正常地重新连接 main 代码块的子项时,
重新组织了子块。
saveConnections
应接受“顶部块”由您的decompose
退回
函数作为参数。如果定义了 saveConnections
函数,则 Blockly
会先调用它,然后再调用 compose
。
saveConnections: function(topBlock) {
// First we get the first sub-block (which represents an input on our main block).
var itemBlock = topBlock.getInputTargetBlock('STACK');
// Then we go through and assign references to connections on our main block
// (input.connection.targetConnection) to properties on our sub blocks
// (itemBlock.valueConnection_).
var i = 0;
while (itemBlock) {
// `this` refers to the main block (which is being "mutated").
var input = this.getInput('ADD' + i);
// This is the important line of this function!
itemBlock.valueConnection_ = input && input.connection.targetConnection;
i++;
itemBlock = itemBlock.nextConnection &&
itemBlock.nextConnection.targetBlock();
}
},
正在注册
赋值函数只是一种特殊的扩展, 然后才能在块类型的 JSON 定义。
// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);
// Example call.
Blockly.Extensions.registerMutator(
'controls_if_mutator',
{ /* mutator methods */ },
undefined,
['controls_if_elseif', 'controls_if_else']);
name
:一个字符串,用于与更改器关联,以便在 JSON 中使用。mixinObj
:包含各种变更方法的对象。例如:saveExtraState
和loadExtraState
。opt_helperFn
:可选的辅助函数, 在 Mixin 混合后在该块上运行。opt_blockList
:可选的块类型数组(作为字符串),将 添加到默认更改器界面中的浮出控件(如果这些界面方法也 。
请注意,与扩展程序不同,每种块类型只能有一个更改器。
{
//...
"mutator": "controls_if_mutator"
}
辅助函数
增值器可以与 mixin 一起注册辅助函数。此函数 在创建指定类型的每个块后运行,并且 mixinObj 是 已添加。它可用于向变更添加其他触发器或效果。
例如,您可以在类似列表的代码块中添加一个帮助程序, 初始商品数量:
var helper = function() {
this.itemCount_ = 5;
this.updateShape();
}