vue + blockly 自定义块、工具箱、主题
自定义块建议使用 Blockly Developer Tools 方便而且选择多样,随时生成块代码。
自定义块
- 块由三个组件组成:
- 块定义对象:定义块的外观和行为,包括文本、颜色、字段和连接。
- 工具箱引用:对工具箱 XML 中块类型的引用,因此用户可以将其添加到工作区。
- 生成器函数:生成此块的代码字符串。它总是用 JavaScript 编写,即使目标语言不是 JavaScript。
- 通过 Blockly Developer Tools 定义文本块
- xml 定义
<xml style="height: 100%">
<category name="自定义">
<block type="custom_text_block"></block>
</category>
</xml>
注意block type 为 custom_text_block
- 初始化 custom_text_block 块
initCustomTectBlock () {
Blockly.Blocks['custom_text_block'] = {
init: function() {
this.appendDummyInput()
.appendField(new Blockly.FieldLabelSerializable("名称"), "TEXT_NAME")
.appendField(new Blockly.FieldTextInput("张三丰"), "TEXT_INPUT");
this.setOutput(true, null);
this.setColour(105);
this.setTooltip("");
this.setHelpUrl("");
}
};
}
代码直接复制开发工具中对应的javascript 代码即可
-
效果如下
-
整体代码示例
<template>
<div id="blocklyDiv" style="height: 800px; width: 100%;"></div>
</template>
<script>
import Blockly from 'blockly';
import * as Ch from 'blockly/msg/zh-hans';
Blockly.setLocale(Ch);
export default {
data () {
return {
workspace: null,
toolboxXml: `
<xml style="height: 100%">
<category name="自定义">
<block type="custom_text_block"></block>
</category>
</xml>
`
}
},
mounted () {
this.workspace = Blockly.inject('blocklyDiv', { toolbox: this.toolboxXml});
this.initCustomTectBlock();
},
methods: {
initCustomTectBlock () {
Blockly.Blocks['custom_text_block'] = {
init: function() {
this.appendDummyInput()
.appendField(new Blockly.FieldLabelSerializable("名称"), "TEXT_NAME")
.appendField(new Blockly.FieldTextInput("张三丰"), "TEXT_INPUT");
this.setOutput(true, null);
this.setColour(105);
this.setTooltip("");
this.setHelpUrl("");
}
};
}
}
}
</script>
</script>
自定义主题
主题名称为 CUSTOM_THEME
- 主题定义
customTheme () {
Blockly.Themes.CUSTOM_THEME = Blockly.Theme.defineTheme('CUSTOM_THEME', {
'base': Blockly.Themes.Classic,
'categoryStyles': {
'custom_category': {
'colour': "#5ba5a5" // 工具箱颜色标识
},
},
'blockStyles': {
// 块样式目前由四个字段组成:colourPrimary、colourSecondary、colorTertiary 和 hat。
'custom_text_blocks': {
'colourPrimary': "#5ba5a5", //块的背景色,可以用色调或十六进制值定义
'colourSecondary':"#5ba5a5", // 如果块是阴影块,则使用此颜色
'colourTertiary':"#C5EAFF" // 块的边框颜色
}
},
'componentStyles': {
'workspaceBackgroundColour': '#131313', // 工作区背景色
'toolboxBackgroundColour': '#2f2e2b', // 工具箱背景色
'toolboxForegroundColour': '#f5f5f5', // 工具箱类别文字颜色
'flyoutBackgroundColour': '#252526', // 弹出背景颜色
'flyoutForegroundColour': '#333', // 弹出标签文本颜色
'flyoutOpacity': 1, // 弹出不透明度
'scrollbarColour': '#dcdcdc', // 滚动条颜色
'scrollbarOpacity': 0.4, // 滚动条不透明度
'insertionMarkerColour': '#f5f5f5', // 插入标记颜色(不接受颜色名称)
'insertionMarkerOpacity': 0.3, // 插入标记不透明度
'cursorColour': '#f5f5f5', // 键盘导航模式下显示的光标颜色
}
});
},
blockStyles
样式定义完成需要在Blockly.Blocks['custom_text_block']
方法中加入this.setStyle("custom_text_blocks");
即可显示该样式。
- 主题引入
Blockly.inject('blocklyDiv', { toolbox: this.toolboxXml, theme: Blockly.Themes.CUSTOM_THEME});
- 效果如下
- 代码示例
<template>
<div id="blocklyDiv" style="height: 800px; width: 100%;"></div>
</template>
<script>
import Blockly from 'blockly';
import * as Ch from 'blockly/msg/zh-hans';
Blockly.setLocale(Ch);
export default {
data () {
return {
workspace: null,
toolboxXml: `
<xml style="height: 100%">
<category name="自定义" categorystyle="custom_category">
<block type="custom_text_block"></block>
</category>
</xml>
`
}
},
mounted () {
this.customTheme();
this.workspace = Blockly.inject('blocklyDiv', { toolbox: this.toolboxXml, theme: Blockly.Themes.CUSTOM_THEME});
this.initCustomTectBlock();
},
methods: {
initCustomTectBlock () {
Blockly.Blocks['custom_text_block'] = {
init: function() {
this.appendDummyInput()
.appendField(new Blockly.FieldLabelSerializable("名称"), "TEXT_NAME")
.appendField(new Blockly.FieldTextInput("张三丰"), "TEXT_INPUT");
this.setOutput(true, null);
this.setTooltip("");
this.setHelpUrl("");
this.setStyle('custom_text_blocks')
}
};
},
customTheme () {
Blockly.Themes.CUSTOM_THEME = Blockly.Theme.defineTheme('CUSTOM_THEME', {
'base': Blockly.Themes.Classic,
'categoryStyles': {
'custom_category': {
'colour': "#5ba5a5" // 工具箱颜色标识
},
},
'blockStyles': {
// 块样式目前由四个字段组成:colourPrimary、colourSecondary、colorTertiary 和 hat。
'custom_text_blocks': {
'colourPrimary': "#5ba5a5", //块的背景色,可以用色调或十六进制值定义
'colourSecondary':"#5ba5a5", // 如果块是阴影块,则使用此颜色
'colourTertiary':"#C5EAFF" // 块的边框颜色
}
},
'componentStyles': {
'workspaceBackgroundColour': '#131313', // 工作区背景色
'toolboxBackgroundColour': '#2f2e2b', // 工具箱背景色
'toolboxForegroundColour': '#f5f5f5', // 工具箱类别文字颜色
'flyoutBackgroundColour': '#252526', // 弹出背景颜色
'flyoutForegroundColour': '#333', // 弹出标签文本颜色
'flyoutOpacity': 1, // 弹出不透明度
'scrollbarColour': '#dcdcdc', // 滚动条颜色
'scrollbarOpacity': 0.4, // 滚动条不透明度
'insertionMarkerColour': '#f5f5f5', // 插入标记颜色(不接受颜色名称)
'insertionMarkerOpacity': 0.3, // 插入标记不透明度
'cursorColour': '#f5f5f5', // 键盘导航模式下显示的光标颜色
}
});
}
}
}
</script>
自定义工具箱
- 定义工具箱
<xml style="height: 100%">
<category name="创建" custom="CREATE_TYPED_VARIABLE"></category>
</xml>
注意 custom="CREATE_TYPED_VARIABLE"
这是唯一标识,注册与给定键CREATE_TYPED_VARIABLE
关联的回调函数,该回调函数中创建该工具箱内按钮。
- 注册工具箱
registerToolboxCategory () {
this.workspace.registerToolboxCategoryCallback( 'CREATE_TYPED_VARIABLE', this.createFlyout);
this.registerButton();
},
// 创建变量
createFlyout (workspace) {
let xmlList = [];
const button = document.createElement('button');
button.setAttribute('text', '添加变量块');
button.setAttribute('callbackKey', 'ADD_VAR_BLOCK');
xmlList.push(button);
const blockList = Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace);
xmlList = blockList.concat(xmlList);
return xmlList;
},
注意 ADD_VAR_BLOCK"
这是唯一标识,注册与给定键ADD_VAR_BLOCK
关联的回调函数,该回调函数进一步处理需求。
- 注册工具箱内按钮
registerButton () {
this.workspace.registerButtonCallback( 'ADD_VAR_BLOCK', this.buttonClickCallbackEvent);
},
buttonClickCallbackEvent (e) {
console.log(e);
},
-
效果如下
-
示例演示
样式请自行忽略
通过点击工具箱内按钮并弹框且添加变量
效果图1:
效果图2: -
示例演示完整代码
<template>
<div class="blockly-contant">
<div id="blocklyDiv" style="height: 800px; width: 100%;"></div>
<el-dialog
title="添加块"
:visible.sync="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form label-position="top" label-width="80px" :model="formLabelAlign">
<el-form-item label="变量名">
<el-input v-model="formLabelAlign.name"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addBlockEvent">添 加</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Blockly from 'blockly';
import * as Ch from 'blockly/msg/zh-hans';
Blockly.setLocale(Ch);
export default {
data () {
return {
workspace: null,
dialogVisible: false,
toolboxXml: `
<xml style="height: 100%">
<category name="创建" custom="CREATE_TYPED_VARIABLE"></category>
</xml>
`,
formLabelAlign: {
name: ''
}
}
},
mounted () {
this.workspace = Blockly.inject('blocklyDiv', { toolbox: this.toolboxXml});
this.registerToolboxCategory();
},
methods: {
// 注册工具箱
registerToolboxCategory () {
this.workspace.registerToolboxCategoryCallback( 'CREATE_TYPED_VARIABLE', this.createFlyout);
this.registerButton();
},
// 注册工具箱内按钮
registerButton () {
this.workspace.registerButtonCallback( 'ADD_VAR_BLOCK', this.buttonClickCallbackEvent);
},
// 工具箱内按钮生成
createFlyout (workspace) {
let xmlList = [];
const button = document.createElement('button');
button.setAttribute('text', '添加变量块');
button.setAttribute('callbackKey', 'ADD_VAR_BLOCK');
xmlList.push(button);
const blockList = Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace);
xmlList = blockList.concat(xmlList);
return xmlList;
},
// 按钮点击事件
buttonClickCallbackEvent (e) {
this.dialogVisible = true;
},
// 点击添加
addBlockEvent () {
let name = this.formLabelAlign.name;
this.createVariable(name)
},
// 创建变量块
createVariable (name) {
let [text, type, msg] = [this.getValidInput(name), '', ''];
if (text) {
const existing = Blockly.Variables.nameUsedWithAnyType(text, this.workspace);
if (existing) {
if (existing.type === type) {
msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS'].replace( '%1', existing.name);
} else {
msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'];
msg = msg.replace('%1', existing.name).replace('%2', this.getDisplayName(existing.type));
}
this.$message({message: msg, type: 'warning'})
} else {
this.workspace.createVariable(text, type);
}
}
if (!msg) {
this.workspace.createVariable(text, type);
this.dialogVisible = false;
}
},
// 类型判断
getDisplayName(type) {
for (let i = 0; i < this.types_.length; i++) {
const typeNames = this.types_[i];
if (type === typeNames[1]) {
return typeNames[0];
}
}
return '';
},
// 获取名称
getValidInput(newVar) {
if (newVar) {
newVar = newVar.replace(/[\s\xa0]+/g, ' ').trim();
if (newVar === Blockly.Msg['RENAME_VARIABLE'] ||
newVar === Blockly.Msg['NEW_VARIABLE']) {
newVar = null;
}
}
return newVar;
},
}
}
</script>
<style>
.blockly-contant /deep/ .el-dialog {
text-align: left !important;
}
</style>