工具箱是使用者封鎖畫面的位置。通常會顯示在工作區的某一側。有時這裡有類別,有時則不會顯示。
本頁主要著重於如何指定工具箱的「結構」 (也就是所謂的類別,以及包含的區塊)。如要進一步瞭解如何變更工具箱的 UI,請參閱自訂 Blockly 工具箱程式碼研究室和 2021 Toolbox API 說明。
格式
Blockly 可讓您使用幾種不同格式指定工具箱的結構。新建議格式採用 JSON,舊格式則使用 XML。
以下是指定上述工具箱的各種方式:
JSON
自 2020 年 9 月版本起,您可以使用 JSON 定義工具箱。
var toolbox = {
"kind": "flyoutToolbox",
"contents": [
{
"kind": "block",
"type": "controls_if"
},
{
"kind": "block",
"type": "controls_whileUntil"
}
]
};
var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
XML
<xml id="toolbox" style="display: none">
<block type="controls_if"></block>
<block type="controls_whileUntil"></block>
</xml>
<script>
var workspace = Blockly.inject('blocklyDiv',
{toolbox: document.getElementById('toolbox')});
</script>
XML 字串
var toolbox = '<xml>' +
'<block type="controls_if"></block>' +
'<block type="controls_whileUntil"></block>' +
'</xml>';
var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
類別
工具箱中的方塊可以依類別整理。
以下說明如何定義上述工具箱,工具箱包含兩個類別 (「Control」和「Logic」),且每個類別皆包含區塊:
JSON
{
"kind": "categoryToolbox",
"contents": [
{
"kind": "category",
"name": "Control",
"contents": [
{
"kind": "block",
"type": "controls_if"
},
]
},
{
"kind": "category",
"name": "Logic",
"contents": [
{
"kind": "block",
"type": "logic_compare"
},
{
"kind": "block",
"type": "logic_operation"
},
{
"kind": "block",
"type": "logic_boolean"
}
]
}
]
}
XML
<xml id="toolbox" style="display: none">
<category name="Control">
<block type="controls_if"></block>
<category name="Logic">
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_boolean"></block>
</category>
</xml>
巢狀類別
類別可在其他類別中建立巢狀結構。有兩個頂層類別 (「Core」和「自訂」),第二個類別包含兩個子類別,每個類別都包含區塊:
請注意,類別可能會同時包含子類別「和」區塊。在上述範例中,「Custom」有兩個子類別 (「Move」和「Turn」),以及自己的區塊 (「start」)。
JSON
{
"kind": "categoryToolbox",
"contents": [
{
"kind": "category",
"name": "Core",
"contents": [
{
"kind": "block",
"type": "controls_if"
},
{
"kind": "block",
"type": "logic_compare"
},
]
},
{
"kind": "category",
"name": "Custom",
"contents": [
{
"kind": "block",
"type": "start"
},
{
"kind": "category",
"name": "Move",
"contents": [
{
"kind": "block",
"type": "move_forward"
}
]
},
{
"kind": "category",
"name": "Turn",
"contents": [
{
"kind": "block",
"type": "turn_left"
}
]
}
]
}
]
}
XML
<xml id="toolbox" style="display: none">
<category name="Core">
<block type="controls_if"></block>
<block type="logic_compare"></block>
</category>
<category name="Custom">
<block type="start"></block>
<category name="Move">
<block type="move_forward"></block>
</category>
<category name="Turn">
<block type="turn_left"></block>
</category>
</category>
</xml>
動態類別
動態類別是系統在每次開啟函式時,根據函式以動態方式填入的類別。
透過已註冊的字串鍵,將類別與函式建立關聯,藉此區塊支援此功能。此函式應傳回類別內容的定義 (包括區塊、按鈕、標籤等)。雖然建議使用 JSON,但內容可以指定為 JSON 或 XML。
另請注意,函式會提供目標工作區做為參數,因此動態類別中的區塊可以根據工作區的狀態。
JSON
自 2021 年 9 月起,您可以在不使用 'blockxml'
的情況下指定區塊狀態,
// Returns an array of objects.
var coloursFlyoutCallback = function(workspace) {
// Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
var colourList = getPalette();
var blockList = [];
for (var i = 0; i < colourList.length; i++) {
blockList.push({
'kind': 'block',
'type': 'colour_picker',
'fields': {
'COLOUR': colourList[i]
}
});
}
return blockList;
};
// Associates the function with the string 'COLOUR_PALETTE'
myWorkspace.registerToolboxCategoryCallback(
'COLOUR_PALETTE', coloursFlyoutCallback);
舊版 JSON
在 2021 年 9 月推出之前,您必須使用 'blockxml'
屬性指定區塊狀態。
// Returns an array of objects.
var coloursFlyoutCallback = function(workspace) {
// Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
var colourList = getPalette();
var blockList = [];
for (var i = 0; i < colourList.length; i++) {
blockList.push({
'kind': 'block',
'type': 'colour_picker', // Type is optional if you provide blockxml
'blockxml': '<block type="colour_picker">' +
'<field name="COLOUR">' + colourList[i] + '</field>' +
'</block>'
});
}
return blockList;
};
// Associates the function with the string 'COLOUR_PALETTE'
myWorkspace.registerToolboxCategoryCallback(
'COLOUR_PALETTE', coloursFlyoutCallback);
XML
// Returns an arry of XML nodes.
var coloursFlyoutCallback = function(workspace) {
// Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
var colourList = getPalette();
var blockList = [];
for (var i = 0; i < colourList.length; i++) {
var block = document.createElement('block');
block.setAttribute('type', 'colour_picker');
var field = document.createElement('field');
field.setAttribute('name', 'COLOUR');
field.innerText = colourList[i];
block.appendChild(field);
blockList.push(block);
}
return blockList;
};
// Associates the function with the string 'COLOUR_PALETTE'
myWorkspace.registerToolboxCategoryCallback(
'COLOUR_PALETTE', coloursFlyoutCallback);
動態類別函式與字串鍵 (即已註冊) 建立關聯後,您可以將這個字串鍵指派給類別定義中的 custom
屬性,讓類別成為動態類別。
JSON
{
"kind": "category",
"name": "Colours",
"custom": "COLOUR_PALETTE"
}
XML
<category name="Colours" custom="COLOUR_PALETTE"></category>
內建動態類別
Blockly 提供三個內建的動態類別。
JSON
{
"kind": "category",
"name": "Variables",
"custom": "VARIABLE"
},
{
"kind": "category",
"name": "Variables",
"custom": "VARIABLE_DYNAMIC"
},
{
"kind": "category",
"name": "Functions",
"custom": "PROCEDURE"
}
XML
<category name="Variables" custom="VARIABLE"></category>
<category name="Variables" custom="VARIABLE_DYNAMIC"></category>
<category name="Functions" custom="PROCEDURE"></category>
注意:「程序」這個詞在整個 Blockly 程式碼集中都使用,但學生已經可以理解「函式」一詞。很抱歉造成你的不便。
停用中
停用的類別不允許使用者開啟該類別,而會在鍵盤瀏覽期間略過該類別。
var category = toolbox.getToolboxItems()[0];
category.setDisabled('true');
停用類別時,系統會將 'disabled'
屬性新增至 DOM 元素,讓您控制已停用類別的外觀。
.blocklyToolboxCategory[disabled="true"] {
opacity: .5;
}
正在隱藏
隱藏的類別不會顯示在工具方塊中。隱藏的類別之後可透過 JavaScript 顯示。
JSON
{
"kind": "category",
"name": "...",
"hidden": "true"
}
XML
<category name="..." hidden="true"></category>
JavaScript
var category = toolbox.getToolboxItems()[0];
category.hide();
// etc...
category.show();
展開中
這僅適用於包含其他巢狀類別的類別。
展開的類別會顯示子類別。根據預設,巢狀類別會處於收合狀態,需要按一下才能展開。
JSON
{
"kind": "category",
"name": "...",
"expanded": "true"
}
XML
<category name="..." expanded="true"></sep>
樣式
Blockly 提供預設類別 UI,以及一些基本樣式選項。如要瞭解如何執行 UI 的進階樣式/設定,請參閱自訂 Blockly 工具箱程式碼研究室,以及 2021 Toolbox API 簡介。
主題
「Themes」可讓您一次指定工作區的所有顏色,包括類別的顏色。
如要使用這些參數,您必須將類別與特定的類別樣式建立關聯:
JSON
{
"kind": "category",
"name": "Logic",
"categorystyle": "logic_category"
}
XML
<category name="Logic" categorystyle="logic_category"></category>
色款
您也可以直接指定顏色,但我們不建議這麼做。顏色是指定色調的字串數字 (0-360)。請注意英國的拼字。
JSON
{
"contents": [
{
"kind": "category",
"name": "Logic",
"colour": "210"
},
{
"kind": "category",
"name": "Loops",
"colour": "120"
}
]
}
XML
<xml id="toolbox" style="display: none">
<category name="Logic" colour="210">...</category>
<category name="Loops" colour="120">...</category>
<category name="Math" colour="230">...</category>
<category name="Colour" colour="20">...</category>
<category name="Variables" colour="330" custom="VARIABLE"></category>
<category name="Functions" colour="290" custom="PROCEDURE"></category>
</xml>
請注意,我們也支援使用可本地化的色彩參照。
類別 CSS
如需更強大的自訂功能,Blockly 也可讓您為預設 UI 的不同元素指定 CSS 類別。然後,您可以使用 CSS 設定樣式
下列元素類型可套用 CSS 類別:
- container - 類別的父項 div 類別。預設的
blocklyToolboxCategory
。 - bar - 包含類別標籤和圖示的 div 類別。預設的
blocklyTreeRow
。 - icon - 類別圖示的類別。預設
blocklyTreeIcon
。 - label - 類別標籤的類別。預設
blocklyTreeLabel
。 - selected - 會在選取類別時新增至類別。預設的
blocklyTreeSelected
。 - openicon - 當類別有巢狀類別且已開啟時,在圖示中新增類別。預設
blocklyTreeIconOpen
。 - 關閉圖示 - 當類別包含巢狀類別且已關閉時,在圖示中新增類別。預設
blocklyTreeIconClosed
。
以下說明使用任一格式指定類別的方式:
JSON
使用 cssConfig 屬性設定特定元素類型的 CSS 類別。
{
"kind": "category",
"name": "...",
"cssConfig": {
"container": "yourClassName"
}
}
XML
如要設定特定元素類型的 CSS 類別,請在該元素類型的前面加上「css」值。
<category name="..." css-container="yourClassName"></category>
存取
有兩種方式可以透過程式輔助方式存取類別。您可以依索引進行存取 (其中 0 是頂層類別):
var category = toolbox.getToolboxItems()[0];
或依 ID:
var category = toolbox.getToolboxItemById('categoryId');
此工具方塊定義中會指定 ID 的位置:
JSON
{
"kind": "category",
"name": "...",
"toolboxitemid": "categoryId"
}
XML
<category name="..." toolboxitemid="categoryId"></category>
預設模塊
工具箱定義可能包含的區塊,可能將欄位設為預設值,或是有已連接的區塊。
有四個區塊:
- 沒有預設值的簡單
logic_boolean
區塊:
math_number
區塊經過修改,顯示數字 42,而非預設的 0:
controls_for
區塊包含三個math_number
區塊:
math_arithmetic
區塊連結了兩個math_number
陰影區塊:
以下是包含這四個區塊的工具箱定義:
JSON
自 2021 年 9 月起,您可以使用 'blockxml'
指定區塊清除狀態。
{
"kind": "flyoutToolbox",
"contents": [
{
"kind": "block",
"type": "logic_boolean"
},
{
"kind": "block",
"type": "math_number",
"fields": {
"NUM": 42
}
},
{
"kind": "block",
"type": "controls_for",
"inputs": {
"FROM": {
"block": {
"type": "math_number",
"fields": {
"NUM": 1
}
}
},
"TO": {
"block": {
"type": "math_number",
"fields": {
"NUM": 10
}
}
},
"BY": {
"block": {
"type": "math_number",
"fields": {
"NUM": 1
}
}
},
}
},
{
"kind": "block",
"type": "math_arithmetic",
"fields": {
"OP": "ADD"
},
"inputs": {
"A": {
"shadow": {
"type": "math_number",
"fields": {
"NUM": 1
}
}
},
"B": {
"shadow": {
"type": "math_number",
"fields": {
"NUM": 1
}
}
}
}
},
]
}
舊版 JSON
在 2021 年 9 月推出之前,您必須使用 'blockxml'
屬性指定區塊狀態。
{
"kind": "flyoutToolbox",
"contents": [
{
"kind": "block",
"type": "logic_boolean"
},
{
"kind": "block",
"blockxml":
'<block type="math_number">' +
'<field name="NUM">42</field>' +
'</block>'
},
{
"kind": "block",
"blockxml":
'<block type="controls_for">' +
'<value name="FROM">' +
'<block type="math_number">' +
'<field name="NUM">1</field>' +
'</block>' +
'</value>' +
'<value name="TO">' +
'<block type="math_number">' +
'<field name="NUM">10</field>' +
'</block>' +
'</value>' +
'<value name="BY">' +
'<block type="math_number">' +
'<field name="NUM">1</field>' +
'</block>' +
'</value>' +
'</block>'
},
{
"kind": "block",
"blockxml":
'<block type="math_arithmetic">' +
'<field name="OP">ADD</field>' +
'<value name="A">' +
'<shadow type="math_number">' +
'<field name="NUM">1</field>' +
'</shadow>' +
'</value>' +
'<value name="B">' +
'<shadow type="math_number">' +
'<field name="NUM">1</field>' +
'</shadow>' +
'</value>' +
'</block>'
},
]
}
XML
<xml id="toolbox" style="display: none">
<block type="logic_boolean"></block>
<block type="math_number">
<field name="NUM">42</field>
</block>
<block type="controls_for">
<value name="FROM">
<block type="math_number">
<field name="NUM">1</field>
</block>
</value>
<value name="TO">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
<value name="BY">
<block type="math_number">
<field name="NUM">1</field>
</block>
</value>
</block>
<block type="math_arithmetic">
<field name="OP">ADD</field>
<value name="A">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
<value name="B">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
</block>
</xml>
用手寫出這些定義可能會...有些痛苦。您可以改為將區塊載入工作區,然後執行下列程式碼取得定義。這些呼叫之所以有效,是因為工具箱對區塊採用與序列化系統相同的格式。
JSON
console.log(Blockly.serialization.workspaces.save(Blockly.getMainWorkspace()));
XML
console.log(Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()));
您也可以移除 x
、y
和 id
屬性,因為工具箱會忽略這些屬性。
陰影設定方塊
陰影區塊是可執行多項函式的預留位置區塊:
- 它們會指出上層區塊的預設值。
- 可讓使用者直接輸入值,而不必擷取數字或字串區塊。
- 這與一般區塊不同,如果使用者在上方拖曳區塊,即可取代這些區塊。
- 可告知使用者預期的值類型。
停用的封鎖條件
您無法從工具箱拖曳已停用的封鎖程式。您可以使用選用的 disabled
屬性個別停用封鎖功能。
JSON
{
"kind": "flyoutToolbox",
"contents": [
{
"kind": "block",
"type":"math_number"
},
{
"kind": "block",
"type": "math_arithmetic"
},
{
"kind": "block",
"type": "math_single",
"disabled": "true"
}
]
}
XML
<xml id="toolbox" style="display: none">
<block type="math_number"></block>
<block type="math_arithmetic"></block>
<block type="math_single" disabled="true"></block>
</xml>
您也可以透過程式輔助方式,使用 setEnabled
停用或啟用區塊。
變數欄位
變數欄位位於工具箱和單純序列化時,可能需要以不同的方式指定。
特別是當變數欄位通常序列化為 JSON 時,只會包含其所代表變數的 ID,因為變數的名稱和類型會分開序列化。然而,工具箱並不包含這類資訊,因此您必須直接加入變數欄位。
{
"kind": "flyoutToolbox",
"content": [
{
"type": "controls_for",
"fields": {
"VAR": {
"name": "index",
"type": "Number"
}
}
}
]
}
分隔符
在任兩個類別之間加入分隔符,即可在兩個類別之間建立行和額外空間。
您可以在 JSON 或 XML 工具箱定義中變更分隔符的類別。
JSON
{
"kind": "sep",
"cssConfig": {
"container": "yourClassName"
}
}
XML
<sep css-container="yourClassName"></sep>
在任兩個區塊之間加入分隔符,即可形成區塊之間的間距。根據預設,每個區塊的鄰近區域都會與鄰近區域間隔 24 像素。您可以使用「間隔」屬性變更這項分隔,這將取代預設的差距。
這可讓您在工具箱中建立區塊的邏輯群組。
JSON
{
"kind": "flyoutToolbox",
"contents": [
{
"kind": "block",
"type":"math_number"
},
{
"kind": "sep",
"gap": "32"
},
{
"kind": "block",
"blockxml": "<block type='math_arithmetic'><field name='OP'>ADD</field></block>"
},
{
"kind": "sep",
"gap": "8"
},
{
"kind": "block",
"blockxml": "<block type='math_arithmetic'><field name='OP'>MINUS</field></block>"
}
]
}
XML
<xml id="toolbox" style="display: none">
<block type="math_number"></block>
<sep gap="32"></sep>
<block type="math_arithmetic">
<field name="OP">ADD</field>
</block>
<sep gap="8"></sep>
<block type="math_arithmetic">
<field name="OP">MINUS</field>
</block>
</xml>
按鈕和標籤
你可以將按鈕或標籤放在可以加入工具箱中的任何位置。
JSON
{
"kind": "flyoutToolbox",
"contents": [
{
"kind": "block",
"type":"logic_operation"
},
{
"kind": "label",
"text": "A label",
"web-class": "myLabelStyle"
},
{
"kind": "label",
"text": "Another label"
},
{
"kind": "block",
"type": "logic_negate"
},
{
"kind": "button",
"text": "A button",
"callbackKey": "myFirstButtonPressed"
},
{
"kind": "block",
"type": "logic_boolean"
}
]
}
XML
<xml id="toolbox" style="display: none">
<block type="logic_operation"></block>
<label text="A label" web-class="myLabelStyle"></label>
<label text="Another label"></label>
<block type="logic_negate"></block>
<button text="A button" callbackKey="myFirstButtonPressed"></button>
<block type="logic_boolean"></block>
</xml>
<style>
.myLabelStyle>.blocklyFlyoutLabelText {
font-style: italic;
fill: green;
}
</style>
您可以指定要套用至按鈕或標籤的 CSS 類別名稱。在上述範例中,第一個標籤使用自訂樣式,第二個標籤則使用預設樣式。
按鈕應有回呼函式,標籤不應。如要為特定按鈕點擊設定回呼,請使用
yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction).
您的函式應接受使用者點選按鈕的引數。變數類別中的「建立變數...」按鈕是包含回呼按鈕的絕佳範例。
變更工具箱
應用程式可以透過單一函式呼叫,隨時變更工具箱中可用的區塊:
workspace.updateToolbox(newTree);
如同初始設定期間的情況,newTree
可以是節點的樹狀結構、字串表示法或 JSON 物件。唯一的限制是模式無法變更;也就是說,如果初始定義的工具箱中有類別,新的工具箱也必須有類別 (但類別可能會變更)。同樣地,如果初始定義的工具箱沒有任何類別,新的工具箱可能就不會有任何類別。
你可以透過以下方式更新單一類別的內容:
var category = workspace.getToolbox().getToolboxItems()[0];
category.updateFlyoutContents(flyoutContents);
其中 flyoutContents 可以是使用 JSON 定義的區塊清單、節點樹狀結構或字串表示法。
請注意,目前更新工具箱會導致部分小幅 UI 重設:
- 在沒有類別的工具方塊中,使用者變更的任何欄位 (例如下拉式選單) 都會還原為預設值。
這裡的現場示範包含類別和區塊群組的樹木。