前言
上一篇文章 Blockly + Vue 之初始化,已经实现了配置官方内置块,并获取对应代码等功能。
本篇文章则主要讲如何实现添加自定义块并对其进行分类显示,然后利用所学,编写一个简单的例子。
目标
- 学会如何将工具箱中的块按分类显示。
- 学会如何添加自定义块,包括不同字段类型,比如图片、下拉菜单、文本输入等。
实现
1. 工具箱块分类显示
在块较多时,我们往往需要将其进行分类显示,方便查找。
其实现方式也很简单,主要是修改 toolbox
配置项里 kind
字段的值,categoryToolbox
为分类工具箱,category
为表示某个分类。
我们将 上一篇文章 的块进行分类显示,修改代码和效果如下:
// 工具箱配置
toolbox: {
// kind,分类,categoryToolbox 为分类工具箱
"kind": "categoryToolbox",
"contents": [
{
// kind,分类,category 为某个分类
"kind": "category",
// 该分类的名字
"name": "逻辑判断",
// 该分类的颜色
"colour": 'red',
"contents": [
{
"kind": "block",
"type": "controls_if"
}
]
},
{
"kind": "category",
"name": "循环",
"colour": 'green',
"contents": [
{
"kind": "block",
"type": "controls_whileUntil"
}
]
}
]
}
2. 添加自定义块
添加自定义块分三步,分别是定义块对象、工具箱引用、生成器函数。
只讲理论不够生动,所以我们结合一个具体的例子来看,比如我们要实现这样的功能,它支持选择不同人物(路飞、索隆)、地点(司法岛、水之都)、行为(说话),然后生成对应代码,点击执行可以看到效果。
2.1 定义块对象
定义块对象,主要是指块的外观和行为,包括颜色、字段等。
一个基本的块定义格式如下,我们拿 Luffy 块为例子:
{
// type 为自定义块的类型名称
"type": "Luffy",
// message0 为该块显示的文字,%1 为第一个参数,如果有第二个参数为 %2,以此类推
"message0": "人物:%1",
// args0 参数,支持多个
"args0": [
{
// 字段类型,field_image 为图片
"type": "field_image",
// 图片地址
"src": "static/luffy.jpeg",
// 图片宽、高、alt
"width": 16,
"height": 16,
"alt": "luffy"
}
],
// 块颜色
"colour": "#bb2241",
// 块是否支持后续连接,null 表示任何类型都可以连接,也可指定连接类型
"nextStatement": null,
// 块 tips 提示
"tooltip": "Luffy tips"
}
之后,我们还需要调用 Blockly
方法,通知其定义块的内容,共有以下两种方式:
// 方式一,每次只能定义一个块
Blockly.Blocks['Luffy'] = {
init: function() {
this.jsonInit({
"type": "Luffy",
"message0": "人物:%1",
...
});
}
};
// 方式二,支持通过 JSON 块数组,一次定义多个块
Blockly.defineBlocksWithJsonArray([
{
"type": "Luffy",
"message0": "人物:%1",
...
},
{
"type": "Zoro",
"message0": "人物:%1",
}
])
这样一来,定义块对象的步骤就完成了,是不是很简单。
当然,除了 type
为 field_image
图片类型的字段外,还有 field_dropdown
下拉菜单,field_input
文本输入等。我们拿 Location 块、Speak 块举例,代码如下:
// Location 块,用于选择地点
{
"type": "Location",
"message0": "地点:%1",
"args0": [
{
// 字段类型,field_dropdown 为下拉菜单
"type": "field_dropdown",
// 字段名
"name": "location",
// 下拉选项,item[0] 为显示内容,item[1] 为对于 value 值
"options": [
["司法岛", "EniesLobby.png"],
["水之都", "WaterSeven.jpeg"]
]
},
],
"colour": "#9fff58",
"nextStatement": null,
// 块是否支持前置连接,null 表示任何类型都可以连接,也可指定连接类型
"previousStatement": null,
"tooltip": "Location tips"
}
// Speak 块,用于定义说话内容
{
"type": "Speak",
"message0": "说话:%1",
"args0": [
{
// 字段类型,field_input 为文本输入
"type": "field_input",
// 字段名
"name": "content",
// 默认内容
"text": "",
},
],
"colour": "#de991a",
"nextStatement": null,
"previousStatement": null,
"tooltip": "Speak tips"
}
2.2 工具箱引用
完成定义块对象后,还需要在 toolbox
配置里引用,代码如下:
toolbox: {
"kind": "categoryToolbox",
"contents": [
{
"kind": "category",
"name": "人物",
"colour": '#bb2241',
"contents": [
// 工具箱引入,type 为自定义块对象的类型名称,比如 Luffy、Location 等
{
"kind": "block",
"type": "Luffy",
}
]
}
]
}
以此类推,可以将 2.1 中定义的块都在工具箱中引入并分类,效果如下:
2.3 生成器函数
最后,需要将定义的这些块转为代码,每个块都需要有它对应的生成器函数。一般采用以下标准格式:
// 以 Location 块为例
Blockly.JavaScript['Location'] = function(block) {
// block 为当前块,有很多属性和方法可以调用
// getFieldValue 为获取字段的值
// Location 块对应的代码为调用 location 函数,并将选中的下拉框的值当作参数传递
let argument0 = block.getFieldValue('location');
return `this.location('${argument0}');<br>`;
};
以此类推,可以将 2.1 中定义的块的生成器函数按照需求实现,最终效果如下: