blockly 拖拽式编程,网上以及官方给的样例都是在浏览器生成了可执行代码,对于生产环境中,这是一件危险的事情。笔者大概看了下底层代码,发现官方样例中,刷新浏览器之后已经搭建好的积木还是存在的,然后就看到 blockly 样例中使用 Local Storage 存储了 xml。整个 blockly 中,都是以 xml 来作为构建各种代码的基础。那么是否可以考虑将 xml 上传到服务端,然后再后续使用过程中,需要使用到代码的时候再服务端生成呢?这样不仅可以解决存储空间,而且还能再安全上得到一定的保障。
Blockly 改造,支持服务端生成代码
所需依赖:
xmldom,这里使用 npm install xmldom 来安装
nodejs 环境与浏览器环境还是有很多区别的,nodejs 没有 window
、document
、DOMParser
对象,这里需要特殊处理。
// 将 window对象、document对象引入到全局中
const jsdom = require("jsdom");
const {JSDOM} = jsdom;
const dom = new JSDOM(`<!DOCTYPE html>`);
global.document=dom.window.document;
global.window=dom.window;
// 将DOMParser对象引入到全局中
global.DOMParser = require('xmldom').DOMParser;
接下来,是整个 demo 的样例
"use strict";
const jsdom = require("jsdom");
const {JSDOM} = jsdom;
const dom = new JSDOM(`<!DOCTYPE html>`);
global.DOMParser = require('xmldom').DOMParser;
global.document=dom.window.document;
global.window=dom.window;
module.paths.push('/home/block'); // 手动将blockly代码加入到nodejs环境变量中
global.Blockly=require('blockly_compressed');
Blockly.setLocale = function(locale) {
Blockly.Msg = Object.assign(locale, Blockly.Msg);
}
Blockly.utils.getMessageArray_ = function () {
return Blockly.Msg
}
Blockly.setLocale(require('msg/js/zh-hans'));
Blockly.Blocks = Object.assign(Blockly.Blocks, require('blocks_compressed'));
Blockly.Lua=require('lua_compressed');
let xmlText = `<xml xmlns="https://developers.google.com/blockly/xml">
<variables>
<variable id="wkcRNXB!axVXJUZ8B*AK">x</variable>
<variable id="7;59^~1nmdWQH5EcBD,L">y</variable>
</variables>
<block type="procedures_defreturn" id="C$#!l|ne0q)=Z/2P+avL" x="379" y="92">
<mutation>
<arg name="x" varid="wkcRNXB!axVXJUZ8B*AK"></arg>
<arg name="y" varid="7;59^~1nmdWQH5EcBD,L"></arg>
</mutation>
<field name="NAME">test</field>
<comment pinned="false" h="80" w="160">描述该功能...</comment>
<statement name="STACK">
<block type="procedures_ifreturn" id="l}6,J~qjl\`DEez(G)H(M">
<mutation value="1"></mutation>
<value name="CONDITION">
<block type="logic_compare" id="%~?Of}I]{a{aeQcfmkX!">
<field name="OP">EQ</field>
<value name="A">
<block type="variables_get" id="Id;n^N|lXknyN=ha8GZT">
<field name="VAR" id="wkcRNXB!axVXJUZ8B*AK">x</field>
</block>
</value>
<value name="B">
<block type="text" id="=0;ndIKoz=E#fKlBm=(P">
<field name="TEXT">terst</field>
</block>
</value>
</block>
</value>
<value name="VALUE">
<block type="variables_get" id="(*gQB45%::eQM}edo(Sb">
<field name="VAR" id="7;59^~1nmdWQH5EcBD,L">y</field>
</block>
</value>
</block>
</statement>
<value name="RETURN">
<block type="variables_get" id="4T0+-[Q_$__CUC0$^cr2">
<field name="VAR" id="wkcRNXB!axVXJUZ8B*AK">x</field>
</block>
</value>
</block>
</xml>`;
try {
var xml = Blockly.Xml.textToDom(xmlText);
} catch (e) {
console.log(e);
return
}
var workspace = new Blockly.Workspace();
Blockly.Events.disable(); // 这句话有用,屏蔽了 Cannot read property 'createElementNS' of undefined 报错。
Blockly.Xml.domToWorkspace(xml, workspace);
var code = Blockly.Lua.workspaceToCode(workspace);
console.log(code);