本文基于 Web Blockly,整理一下可视化编程工具 – Blockly 的常用配置,包括:工作区配置、添加自定义块、配置工具箱、配置代码生成器等。
1. 固定尺寸工作区
把 Blockly 放到网页上最简单的方法是将其注入到一个空 div
中。
1.1 引入 Blockly 脚本
首先,引入 Blockly 脚本及核心 “块”:
<script src="blockly_compressed.js"></script>
<script src="blocks_compressed.js"></script>
注意:实际路径可能与上面不同,请按 Blockly 的实际位置调整上面路径
1.2 引入语言文件
引入包含用户语言的消息定义(本例中使用了英语):
<script src="msg/js/en.js"></script>
1.3 确定引入位置
在页面创建一个空div
元素,并设置其尺寸:
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
1.4 添加工具栏
在页面任意位置定义好 “工具栏” 结构(请参阅定义工具箱以获取更多信息):
</block type="controls_if">
</block type="controls_repeat_ext">
</block type="logic_compare">
</block type="math_number">
</block type="math_arithmetic">
</block type="text">
</block type="text_print">
1.5 初始化
最后,调用下面的命令将 Blockly 注入到一个 id 为 blocklyDiv
的空 div
中。这个脚本应该在页面的底部,或者由 onload
事件调用以确保注入代码在页面关键元素加载完后执行。
<script>
var workspace = Blockly.inject('blocklyDiv',
{toolbox: document.getElementById('toolbox')});
</script>
workspace
变量当前并没有被使用,但当需要保存“块”或生成代码时,它会变得非常重要。如果有多个 Blockly 实例注入到同一个页面时,应确保每个返回的工作空间都存储在不同的变量中。
在浏览器中测试页面。你应该可以看到 Blockly 的编辑器填充到了 div 元素中,有七个块积木在工具箱里。这是在线示例。
2. 可调尺寸工作区
一个好的 Web 应用将调整 Blockly 的大小以填充屏幕上的可用空间,而不是将其固定大小。有几种方法可以做到这一点,包括使用 iframe,CSS 和 JavaScript 定位。此页演示了一种强大而灵活的叠加方法。
本示例中只需简单的三步,就可以创建一个非固定尺寸的工作区:
2.1 定义区域
使用 HTML 的table
元素或div
及 CSS,创建一个空区域,页面调整大小时重新排版。并确保该区域有一个唯一的 ID(本例中为blocklyArea
)
这有一个在线示例,在页底部使用table
进行定义。
2.2 注入
与创建固定尺寸工作区一样引入 Blockly,添加脚本、blocklyDiv
元素、工具栏、及初始化脚本。
Blockly 现在应该是在页面上运行的,只是不在它应该在的位置上(可能是在屏幕外)。
2.3 定位
最后一步是将blocklyDiv
元素放在blocklyArea
元素上。这样,就需要移除blocklyDiv
元素的height
、width
样式,并添加绝对定位:
<div id="blocklyDiv" style="position: absolute;"></div>
然后将注入脚本替换成把 blocklyDiv
放置在 blocklyArea
的脚本:
<script>
var blocklyArea = document.getElementById('blocklyArea');
var blocklyDiv = document.getElementById('blocklyDiv');
var workspace = Blockly.inject(blocklyDiv,
{toolbox: document.getElementById('toolbox')});
var onresize = function(e) {
// Compute the absolute coordinates and dimensions of blocklyArea.
var element = blocklyArea;
var x = 0;
var y = 0;
do {
x += element.offsetLeft;
y += element.offsetTop;
element = element.offsetParent;
} while (element);
// Position blocklyDiv over blocklyArea.
blocklyDiv.style.left = x + 'px';
blocklyDiv.style.top = y + 'px';
blocklyDiv.style.width = blocklyArea.offsetWidth + 'px';
blocklyDiv.style.height = blocklyArea.offsetHeight + 'px';
Blockly.svgResize(workspace);
};
window.addEventListener('resize', onresize, false);
onresize();
Blockly.svgResize(workspace);
</script>
这是 Blockly 的在线示例,它填满了整个浏览器屏幕的底部。
3. 添加自定义块(Block
)
虽然 Blockly 已经定义了大量的标准块,但大多数应用仍然需要定义和实现一些自己业务相关的 “块”。
“块” 由三个组件构成:
块(Block)定义对象
– 定义块的外观和行为,包括文本、颜色、字段和连接工具箱(Toolbox)引用
– 工具箱 XML 中对块类型的引用,这样用户才能将其添加到工作区中生成器函数
– 用于生成块的代码字符串。该函数一般情况是使用 JavaScript 编写的,即使目标语言不是 JavaScrpit,基至运行环境也只不是 Web 环境。
3.1 块定义
Blockly 通过 Web 页面中的脚本文件加载 “块”,在blocks/
目录下包含了几个标准块示例。假设你的块不适合现有的类别,就需要创建一个新的包含块定义的 JavaScript 文件,并将其添加到引用页的 <script ...>
标签中。
注意:大多数块都可以使用 Blockly Developer Tools 定义,而不是手动创建下面的代码。
(译者按:谷歌官方不建议手动去编写创建自定义块的代码,而是提供了相关的开发工具。下面的代码是为了熟悉了解对应字段的含义。)
一个典型的块定义类型如下:
JSON
定义格式:
Blockly.Blocks['string_length'] = {
init: function() {
this.jsonInit({
"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"
});
}
};
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');
}
};
以上两种定义形式是等价的。其中:
string_length
– 这是所定义的 “块” 的类型名称。由于所有的块会共享一个相同的命名空间,因此最好使用一个类别名来区分类别(本例中是string
),接下来是你的块函数(本例中是length
)init
– 此函数用于定义块的外观(如形状、颜色、字段等)
上面模块完成定义后,效果如下:
更多关于块定义详情,请参考:块自定
3.2 添加工具箱引用
完成定义后,需要使用类型名,将其添加到工具箱中:
<xml id="toolbox" style="display: none">
<category name="Text">
<block type="string_length"></block>
</category>
...
</xml>
3.3 添加生成器函数
最后,要将块解析成代码,需要定义一个与之相对应的生成器函数。生成器函数由于生成语言的不同也会有所不同,标准的生成器函数格式如下:
Blockly.JavaScript['text_length'] = function(block) {
// String or array length.
var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_FUNCTION_CALL) || '\'\'';
return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER];
};
生成器函数会引用块,以对其进行处理。其输入(如上面的 VALUE
输入)的是代码字符串,然后会将其链接到一个更大的表达式中。
译者按:解析对应的代码需要在 HTML 上引用对应的脚本库。如要解析成 JavaScript 代码需如下引用
<script src="javascript_compressed.js"></script>
有关详细信息,请参阅使用自定义生成器。
4. 工具箱(Toolbox
)配置
工具箱是用户可以创建新 “块” 的侧边菜单。工具箱的结构使用 XML 来指定,它可以是一个节点树,也可以是字符串的形式。所定义的 XML 会在 Blockly 注入到页面中时传递给它。除了手工输入 XML 外,还可以使用 Blockly Developer Tools 来自动生成。
4.1 工具箱定义
以下是一个最小化的工具箱定义示例,在示例中使用了节点定义形式:
<script>
var workspace = Blockly.inject('blocklyDiv',
{toolbox: document.getElementById('toolbox')});
</script>
下面定义是字符串定义形式,两种方式是等价的:
<script>
var toolbox = '<xml>';
toolbox += ' <block type="controls_if"></block>';
toolbox += ' <block type="controls_whileUntil"></block>';
toolbox += '</xml>';
var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
</script>
两种定义方式,都会生成如下工具箱:
如果工具箱中的块比较少量,则可以直接显示它们而不需要使用类别(如上面的最小示例中所示)。在此简单模式下,所有可用块都直接显示在工具箱中,主工作区上没有滚动条,也不需要垃圾桶。
4.2 类别
工具箱中的模块可以类别进行组织。以下示例中,包含了'Control'
和'Logic'
两个分类,每个类别包含三个块:
下面是完成定义后生成的工具箱,单击“逻辑”类别,可以看到弹出窗口中的三个逻辑块,效果如下:
“分类”的存在改变了 Blockly 的 UI,以支持更大的应用。而 “滚动条” 的出现,就提供了一个无限大的工作空间。其它的,如:“垃圾桶”、“上下文菜单(用来添加注释或折叠块)”等,都可以通过配置选项来设置。
定义分类时,可以通过一个colour
属性来指定该分类的颜色。颜色使用 0~360
之间的数字表示色调:
...
...
...
...
设置颜色后,工具栏效果如下:
4.3 动态类别
以下有两个分类'Variables'
和'Functions'
用于指定形为,分类里面并没有内容,但定义分类时添加了'custom'
属性,值可以是'VARIABLE'
或'PROCEDURE'
。这些分类,将使用适合的 “块” 自动填充:
开发者还可以使用custom
属性来创建动态填充弹出类别。例如,要创建一个自定义的弹出颜色块:
- 创建自定义属性:
- 定义提供给分类内容的回调。这个回调应该有一个工作区并返回一个 XML 块元素数组:
/**
* Construct the blocks required by the flyout for the colours category.
* @param {!Blockly.Workspace} workspace The workspace this flyout is for.
* @return {!Array.<!Element>} Array of XML block elements.
*/
myApplication.coloursFlyoutCallback = function(workspace) {
// Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
var colourList = myApplication.getPalette();
var xmlList = [];
if (Blockly.Blocks['colour_picker']) {
for (var i = 0; i < colourList.length; i++) {
var blockText = '' +
'' +
'' + colourList[i] + '' +
'' +
'';
var block = Blockly.Xml.textToDom(blockText).firstChild;
xmlList.push(block);
}
}
return xmlList;
};
- 在工作区注册回调:
myWorkspace.registerToolboxCategoryCallback(
'COLOUR_PALETTE', myApplication.coloursFlyoutCallback);
4.4 类别树
类别可以嵌套在其它类别中。如下所示,有两个顶级类别 Core
和 Custom
,每个类别中又包含了两个子类别,每个子类别同时又包含了若干块:
请注意,类别可以包含子类别和块。在上面的例子中,Custom
有两个子类别(Move
和 Turn
),同时它自身又有一个块(start
)。
加载 Blockly 时,默认情况下会显示折叠类别,但可以使用 “ 来扩展类别。
4.5 块分组
XML 可以包含自定义块或块分组。现在有以下 4 个块:
- 一个简单的
logic_boolean
块:
- 一个
math_number
块,已修改为显示 42 而不是 0:
- 一个
controls_for
块,它连接了三个math_number
块:
- 一个
math_arithmetic
块,连接了两个math_number
“阴影块”:
以下工具栏中生成这四个块的代码:
42
1
10
1
ADD
1
1
这些定制块或组的 XML 与 Blockly 的 XML 存储格式相同。因此,为此类块构造 XML 的最简单方法是使用 Code application 来构建块,然后切换到 XML
选项卡并复制结果。工具箱会忽略 x
,y
和 id
属性,并且可能会将其删除。
4.6 阴影块
阴影块是占位符块,它们可执行多种功能:
- 指示其父块的默认值
- 允许用户直接输入值,而不需要数字或字符串块
- 它们与常规块不同,如果用户在其上放置块,则会被替换
- 它们会提示用户预期的值类型
阴影块不能直接用 Code application 构造,但可以通过替换 XML 中的普通块 和
为 和
来构造。
4.7 分隔器
添加一个 “ 标签到任意两个分类之间,将会创建一个 “分隔器”。
默认情况下,两个相邻块之间的分隔间隔为 24 像素。可以通过修改sep
标签的gap
属性来调整距离:
ADD
MINUS
通过调整块之间的间隙,就可以在工具箱中创建逻辑块组:
4.8 按钮与标签
就像 “块” 一样,你也可以将一个按钮或标签放在工具栏的任何位置:
<label></label>
<label></label>
<style>
.myLabelStyle>.blocklyFlyoutLabelText {<br /> font-style: italic;<br /> fill: green;<br />}<br /></style>
还可以对按钮和标签使用 CSS 样式。在上面示例中,第一个label
标签使用了自定义样式,而button
则使用了默认样式。
按钮需要回调函数,但标签不用。设置按钮点击时的回调函数:
yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction)
函数接受的参数应该是可被点击的按钮。这个在线示例 Variables 类别中的“Create variable…”按钮是一个非常好的带回调的例子可以参考相关的代码。
4.9 禁用
工具箱中的 “块”,可以在 XML 中通过 disabled
属性将其禁用:
禁用块可用于限制用户的选择。这可以在某些场景中运用比如用户完成某些成就后解锁该块:
4.10 Toolbox 的修改
应用可以在任何时候通过调用以下函数来修改工具箱中的可用块:
workspace.updateToolbox(newTree);
在初始配置下,newTree
可能是一个节点树或字符串。唯一的限制就是不能修改模式,也就是说在初始工具箱中定义的类别,那么新工具箱也必须有(尽管类别可能会被更改);同样的,初始工具箱中没有的类别,在新工具箱中也不能有。
注意,更新工具栏可能会导致一些较小的 UI 重置:
- 在一个含有类别的工具箱,如果有弹出菜单,初始是合上的
- 在没有类别的工具箱中,用户更改的任何字段(如下拉列表)都将恢复到默认值
- 任何超长工具箱,如果超出了页面,其滚动条会跳到顶端
这是一个包含类别和块组的工具栏的在线示例。
5. 代码生成器
大多数 Blockly 应用都需要将用户程序转换为 JavaScript、Python、PHP、Lua、Dart 或其它语言,这一转换过程是由 Blockly 客户端完成的。
5.1 生成代码
首先,引入所需生成语言的生成器。Blockly 中包含了以下生成器:
javascript_compressed.js
python_compressed.js
php_compressed.js
lua_compressed.js
dart_compressed.js
生成器类需要在blockly_compressed.js
之后引入。(此处注意引用顺序)如:
<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>
应用调用时,用户块可以随时从应用中导出到代码:
var code = Blockly.JavaScript.workspaceToCode(workspace);
将以上代码中的 JavaScript
替换为 Python
、PHP
、Lua
、或 Dart
就可以生成相应的代码。
5.2 实时生成
Blockly 库生成代码的操作非常得快,所以频繁调用生成函数也不会有问题。这样就可以通过添加 Blockly 事件监听来实时生成代码:
function myUpdateFunction(event) {
var code = Blockly.JavaScript.workspaceToCode(workspace);
document.getElementById('textarea').value = code;
}
workspace.addChangeListener(myUpdateFunction);
有关更多信息,可参阅事件。
6. 网格(Grid
)
6.1 使用网格
Blockly 的主工作区可以有一个网格。而网格可以对块进行分隔,从而实现更整洁清晰的布局。当工作区较大时,这会非常有用。
注入 Blockly 时,可以在其配置选项中启用网格,如下所示:
var workspace = Blockly.inject('blocklyDiv',
{toolbox: document.getElementById('toolbox'),
grid:
{spacing: 20,
length: 3,
colour: '#ccc',
snap: true},
trashcan: true});
6.2 网格配置参数
Spacing(间距)
网格最重要的配置项就是 spacing
,它定义了网格中点的距离。其默认值是0
,其结果是不会有网格。以下演示了分别设置为 10、20、40 时的效果:
Length(长度)
length
是定义网格端点形状的数字。长度为 0 的结果是一个看不见的网格,长度为 1(默认值)会是点,一个更长的长度会导致交叉,长度等于或大于spacing
时将没有间隔。下面是将 length
分别设置为 1、5 和 20 的示例:
Colour(颜色)
colour
属性定义了网格端点的颜色,可以使用任何与 CSS 兼容的格式,如:#f00
、#ff0000
或rgb(255, 0, 0)
,其默认值是#888
。
以下为将 colour
分别设置为 #000
、#ccc
和 #f00
的效果:
Snap(网格对齐)
snap
属性是一个布尔值,用于设置当放置在工作空间时块是否应该锁定到最近的网格点,使其网格对齐。默认值为false
。
7. 缩放(Zoom
)
7.1 使用缩放
Blockly 的主工作区大小是可调的,其大小可以由用户动态控制,或由开发者设置为静态的。
zoom
是 Blocly 的初始化配置项之一:
var workspace = Blockly.inject('blocklyDiv',
{toolbox: document.getElementById('toolbox'),
zoom:
{controls: true,
wheel: true,
startScale: 1.0,
maxScale: 3,
minScale: 0.3,
scaleSpeed: 1.2},
trashcan: true});
7.2 缩放配置参数
controls(控制)
设置为true
时,会显示 zoom-centre(居中)、zoom-in(放大)和 zoom-out(缩小) 三个按钮,默认为 false
。
wheel(滚轮)
设置为 true
时允许鼠标滚轮缩放,默认为false
startScale
初始放大基数。对于多层应用来说,startScale
会在第一层设置一个高级值,这样在子层就可以根据这个值进行更复杂的缩放。默认为 1.0
maxScale
最大可放大倍数,默认为 3
minScale
最小可缩小倍数,默认为 0.3
scaleSpeed
每次放大或缩小时,缩放速度比。即:scale = scaleSpeed ^ steps
。注意,缩小时使用减,而放大时使用加。默认为 1.2
8. 事件
工作区上的每个更改都会触发事件。这些事件完整地描述了每次更改前后的状态。
8.1 事件监听
工作区对象(workspace
)中有 addChangeListener
和 removeChangeListener
两个方法,可用于监听事件流。一个实时生成代码的例子,另一个最多块数量的限制例子。通常情况下,这两个例子都不关心触发事件是什么。他们只是查看工作区的当前状态。
更复杂的事件监听会查看触发事件。在以下示例中,会检测用户创建的第一条评论,然后发出警报,并停止监听,从而不进一步触发警报:
function onFirstComment(event) {
if (event.type == Blockly.Events.CHANGE &&
event.element == 'comment' &&
!event.oldValue && event.newValue) {
alert('Congratulations on creating your first comment!')
workspace.removeChangeListener(onFirstComment);
}
}
workspace.addChangeListener(onFirstComment);
此外,Blockly 还提供了另一种监听事件流的方法,可以在每个 “块” 中定义一个 onchange
函数,该函数会在块发生变化时被调用。
8.2 事件类型
所有事件都具有以下共同属性:
名称 | 类型 | 描述 |
---|---|---|
type |
string | Blockly.Events.CREATE , Blockly.Events.DELETE , Blockly.Events.CHANGE , Blockly.Events.MOVE , Blockly.Events.UI 之一 |
workspaceId |
string | 工作区的 UUID。该工作区可以通过 Blockly.Workspace.getById(event.workspaceId) 找到 |
blockId |
string | 块的 UUID。这个块可以通过 workspace.getBlockById(event.blockId) 找到 |
group |
string | UUID 分组。有些事件是不可分割的组中的一部分。例如,在堆栈中插入语句 |
Blockly.Events.BLOCK_CREATE
块创建事件,其有 2 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
xml |
object | 定义新块及任何连接子块的 XML |
ids |
array | 包含新块及任何连接子块 Id 的数组 |
Blockly.Events.BLOCK_DELETE
块删除事件,其有 2 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
oldXml |
object | 所删除块及任何连接子块的 XML |
ids |
array | 包含所删除块及任何连接子块 UUID 的数组 |
Blockly.Events.BLOCK_CHANGE
块变化事件,其有 4 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
element |
string | field , comment , collapsed , disabled , inline , mutate 之一 |
name |
string | 所更改字段的名称 |
oldValue |
value | 原始值 |
newValue |
value | 修改后的值 |
Blockly.Events.BLOCK_MOVE
块移动事件,其有以下 6 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
oldParentId |
string | 其旧父块的 UUID,当为顶级块时为 Undefined |
oldInputName |
string | 旧输入值,当为顶级块时为 Undefined |
oldCoordinate |
object | 当为顶级块时,则为 X 和 Y 坐标;否则为 Undefined |
newParentId |
string | 其新父块的 UUID,当为顶级块时为 Undefined |
newInputName |
string | 新输入值,当为顶级块时为 Undefined |
newCoordinate |
object | 当为顶级块时,则为 X 和 Y 坐标;否则为 Undefined |
Blockly.Events.VAR_CREATE
变量创建事件,其有 2 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
varType |
string | 变量的类型,如 ‘int’ 或 ‘string’。不需要是唯一的。这将默认为“”,这是一种特定类型 |
varName |
string | 变量名称,注意设定时变量相互之间和程序里要唯一 |
varId |
string | 变量唯一 ID |
Blockly.Events.VAR_DELETE
变量删除事件,其有 2 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
varType |
string | 变量类型,如’int’或’string’。不需要是唯一的。这将默认为“”,这是一种特定类型。 |
varName |
string | 变量名称。注意设定时变量相互之间和程序里要唯一 |
varId |
string | 变量唯一 ID |
Blockly.Events.VAR_RENAME
变量重命名事件,其有 2 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
oldName |
string | 变量的当前名称。注意设定时变量相互之间和程序里要唯一 |
newName |
string | 变量的新名称。注意设定时变量相互之间和程序里要唯一 |
varId |
string | 变量唯一 ID |
Blockly.Events.UI
UI 事件,其有 3 个附加属性:
名称 | 类型 | 描述 |
---|---|---|
element |
string | selected , category , click , commentOpen , mutatorOpen , warningOpen 值之一 |
oldValue |
value | 原始值 |
newValue |
value | 修改后的值 |
预计 UI 事件所代表的 UI 动作列表将随着时间的推移变得更加全面。例如滚动,缩放,拖动气泡等事件。
这里有个在线示例,同一个页面中两个 Blockly 实例,它们通过事件进行同步。
9. 云存储
如果你的应用是托管在云端的,那么你可以使用 Blockly 的云存储功能,并利用这一服务的优势来保存、加载、分享和发布你的程序。
9.1 设置应用引擎
首先,需要将 Blockly 发布到应用引擎上:
- 下载并安装 Python SDK。
- 登录 Google App Engine 并创建应用。
- 编辑
appengine/app.yaml
,并将blockly-demo
中的应用 ID 修改为上一步所创建的 ID。 - 复制(或软链接)以下文件及目录到对应的
appengine/static/
- demos/
- msg/
- media/
- *_compressed.js
- 可选:如果你需要在服务器上使用
blockly_uncompressed.js
,则同样需要将其复制到appengine/static/
。复制core
到appengine/static/
,并复制closure-library/
到上级目录appengine/
。 - 可选:如果需要运行 Blockly Playground,那需要像第 5 步一样,复制
blocks
、generators
和tests
几个目录到指定位置。 - 运行 Google App Engine Launcher,并添加你的
appengine
,然后点击 “Deploy” 按钮。如果习惯使用命令行,那么执行:appcfg.py --oauth2 update appengine/
。
上传 Blockly 后,就可以在浏览器中输入步骤 2 中创建的 URL。然后就能到看到 Demo 列表,包括云存储 Demo。
9.2 云端通讯
在云存储 Demo 的 demos/storage/index.html 文件中有以下特点。
首先,有一个加载云存储 API 的脚本:
<script src="/storage.js"></script>
请注意,该脚本假定页面上只有一个 Blockly 工作区。还有下面这些消息定义,应该根据你自身的需求进行修改:
BlocklyStorage.HTTPREQUEST_ERROR = 'There was a problem with the request.\n';
BlocklyStorage.LINK_ALERT = 'Share your blocks with this link:\n\n%1';
BlocklyStorage.HASH_ERROR = 'Sorry, "%1" doesn\'t correspond with any saved Blockly file.';
BlocklyStorage.XML_ERROR = 'Could not load your saved file.\n' +
'Perhaps it was created with a different version of Blockly?';
将这些消息翻译成其它国家语言的示例,可以参考 Blockly Games 中的 json 目录
保存当前块调用一次 BlocklyStorage.link()
即可:
<button>Save Blocks</button>
在页面加载时重新保存,仅需在 Blockly 注入页面,通过根据 URL 中的 Hash 调用 BlocklyStorage.retrieveXml
:
if ('BlocklyStorage' in window && window.location.hash.length > 1) {
BlocklyStorage.retrieveXml(window.location.hash.substring(1));
}
9.3 本地存储
storage.js
API 还提供了浏览器本地存储能力。这可以用于替代云存储,或二者结合使用。
从本地存储中恢复块,只需要在 Blockly 注入后超时调用 BlocklyStorage.restoreBlocks
即可:
window.setTimeout(BlocklyStorage.restoreBlocks, 0);
在用户离开页面时自动备份到本地存储,可调用 BlocklyStorage.backupOnUnload
实现,且其可以通过监听页面的 unload
事件来自动调用:
BlocklyStorage.backupOnUnload();
示例
一个云存储在线示例
评论功能怎么做的?