區塊應用程式通常會產生 JavaScript 做為輸出語言 通常會在網頁中執行 (可能相同或內嵌 WebView)。 和其他產生器一樣,第一步是導入 JavaScript 產生器。
import {javascriptGenerator} from 'blockly/javascript';
如要從工作區產生 JavaScript,請呼叫:
javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);
產生的程式碼可以直接在到達網頁中執行:
try {
eval(code);
} catch (e) {
alert(e);
}
基本上,以上程式碼片段只會產生程式碼,並進行評估。不過,我們也做了一些精進。其中一個精進項目是,eval 會包裝在 try
/catch
中,以便顯示任何執行階段錯誤,而不會悄悄失敗。另一個修正是將 code
新增至保留清單中
如此一來,如果使用者程式碼中包含該名稱的變數,就會傳回該名稱
物件會自動重新命名,而非設定衝突。任何本機變數都必須
透過這種方式預訂
醒目顯示區塊
在程式碼執行時醒目顯示目前執行的區塊,可協助使用者
瞭解他們的程式行為焦點所在
每個陳述式層級,方法是將 STATEMENT_PREFIX
產生 JavaScript 程式碼:
javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');
定義 highlightBlock
以標記工作區的區塊。
function highlightBlock(id) {
workspace.highlightBlock(id);
}
這會將 highlightBlock('123');
陳述式加到 之前
每個陳述式,其中 123
是要替換的區塊序號
醒目顯示。
無限迴圈
雖然產生的程式碼一定會有語法正確的語法
可能包含無限迴圈自 2019 年以來
暫停問題範圍超出
要處理這些案例,區塊範圍 (!) 是最佳做法
如何保留一個計數器,並在每次執行疊代時減少計數器。
如要完成這項操作,只要將 javascriptGenerator.INFINITE_LOOP_TRAP
設為程式碼即可
這段程式碼會插入每個迴圈和每個函式中。以下是
範例:
window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);
範例
這裡是 現場示範 產生及執行 JavaScript
JS 解譯器
如果您很擅長正確執行使用者封鎖程序,那麼 建議您採用 JS-解譯器專案。 這項專案與 Blockly 不同,但是專為 Blockly 編寫。
- 以任何速度執行程式碼。
- 暫停/繼續/逐步執行。
- 在執行時醒目顯示區塊。
- 與瀏覽器的 JavaScript 完全隔離。
執行翻譯工具
首先,從 GitHub 下載 JS-解譯器:
然後新增至頁面:
<script src="acorn_interpreter.js"></script>
呼叫這個方法最簡單的方法,就是產生 JavaScript、建立 並執行程式碼:
var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
踏出翻譯的第一步
為了放慢程式碼執行速度,或以更多受控的方式執行,請將
利用步驟呼叫 run
(本例中每 10 毫秒一個步驟):
function nextStep() {
if (myInterpreter.step()) {
setTimeout(nextStep, 10);
}
}
nextStep();
請注意,每個步驟都不是一行或區塊,而是在 JavaScript,可能會非常精細
新增 API
JS-解譯器是一種完全獨立於瀏覽器之外的沙箱。 凡是對外部執行動作的區塊,都必須將 API 新增至 第一個輸入字詞如需完整說明,請參閱 JS-解譯器說明文件。 不過,我們先來瞭解支援警示和提示區塊所需的 API:
function initApi(interpreter, globalObject) {
// Add an API function for the alert() block.
var wrapper = function(text) {
return alert(arguments.length ? text : '');
};
interpreter.setProperty(globalObject, 'alert',
interpreter.createNativeFunction(wrapper));
// Add an API function for the prompt() block.
wrapper = function(text) {
return prompt(text);
};
interpreter.setProperty(globalObject, 'prompt',
interpreter.createNativeFunction(wrapper));
}
接著,修改翻譯器初始化來傳入 initApi 函式:
var myInterpreter = new Interpreter(code, initApi);
預設封鎖設定中只有兩項封鎖設定 需要自訂 API 才能使用
正在連結「highlightBlock()
」
在 JS-解譯器中執行時,應執行 highlightBlock()
隨著使用者透過程式執行待辦
這邊建立包裝函式函式 highlightBlock()
來擷取函式
引數並註冊為原生函式。
function initApi(interpreter, globalObject) {
// Add an API function for highlighting blocks.
var wrapper = function(id) {
return workspace.highlightBlock(id);
};
interpreter.setProperty(globalObject, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
較複雜的應用程式可能會為了沒有必要而重複執行步驟 暫停,直到聽見醒目顯示指令後暫停。這項策略會模擬 逐行執行。以下範例使用這個方法。