[blockly 系列] 第 1 篇 環境搭建

johnhuu發表於2019-05-08

blockly 是 google 用於視覺化程式設計的開源庫,可以以積木式程式設計的方式開發程式,沒錯,就是傳說中的通過拖拽寫程式碼。聽起來很離譜但在某些場合有著不可替代的作用,也有一定的商業價值,比如 MIT 與 google 合作出品的 Scratch,通過拖拽的方式生成動畫,是青少年學習程式設計的重要工具,國內在 Scratch 基礎上進行優化的程式設計貓,聽說 B 輪融資了1.2億。

為什麼會研究一下 blockly, 來源於公司專案中一個需求--給使用者提供一個開發者平臺,通過對預定義元件的拖拽和排序來生成可應用於移動端跨平臺的小程式,本著高漲的學習熱情與求知慾(呵呵呵。。。),所以有了這系列文章,一切從一個 demo 開始吧。

環境搭建

學習 blockly 之前, 首先需要從 github 克隆 google/blockly 原始碼到本地,官方提供了很多 demo 來供我們學習使用,先看一下原始碼目錄結構(只展示一級目錄),對搭建環境需要用到的庫做了註釋。

ps: 這個目錄是不是看起來還挺漂亮,此處應該留下連結 mddir

|-- blockly
    |-- .eslintignore
    |-- .eslintrc.json
    |-- .gitignore
    |-- .jshintignore
    |-- .npmrc
    |-- .travis.yml
    |-- blockly_accessible_compressed.js
    |-- blockly_accessible_uncompressed.js
    |-- blockly_compressed.js // 核心庫
    |-- blockly_uncompressed.js
    |-- blocks_compressed.js // 核心庫
    |-- build.py
    |-- dart_compressed.js
    |-- gulpfile.js
    |-- javascript_compressed.js // js程式碼生成器
    |-- LICENSE
    |-- lua_compressed.js
    |-- package.json
    |-- php_compressed.js
    |-- python_compressed.js
    |-- README.md
    |-- .github
    |-- accessible
    |-- appengine
    |-- blocks
    |-- core
    |-- externs
    |-- generators
    |-- i18n
    |-- local_build
    |   |-- local_build.sh
    |-- media
    |-- msg
    |   |-- zh-hans.js // 簡體中文語言包
    
複製程式碼

新建一個 index.html 檔案,通過引入外部資源方式移入 js 檔案,像這樣下面這樣我們就完成了環境的搭建,在實際專案中可能需要在 vue | react 這樣的前端框架中使用 blockly,這個可以後邊詳細討論,無論如何,我們先完成一個最簡單的示例。

    <script src="./static/blockly_compressed.js"></script>
    <script src="./static/blocks_compressed.js"></script>
    <script src="./static/javascript_compressed.js"></script>
    <script src="./static/msg/js/zh-hans.js"></script>
複製程式碼

定義一個 block (視覺化程式碼塊)

搭建好環境,我們就可以進入開發了,比如先輸出一個 'hello world'。blockly 中使用 xml 定義一個 block,可以通過標籤方式引入到工作區, 比如 <block type="hello"></block> 這樣就引入了一個 name 為 hello 的程式碼塊,下面的程式碼展示了 hello 這個 block 是如何定義的,自定義程式碼塊是使用 blockly 的核心,由於內容比較多就放到下一篇詳細介紹。

// 通過 js 定義一個程式碼塊
Blockly.Blocks['hello'] = {
  init: function() {
    this.appendDummyInput()
    .appendField("輸出")
    .appendField(new Blockly.FieldTextInput("hello world"), "say_content");
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(230);
 this.setTooltip("");
 this.setHelpUrl("");
  }
};


複製程式碼

定義一個 block 有兩種方式 js | json , 既然 js 可以搞定,為毛又搞個 json? 下面是官方給的解釋,可以看出通過 json 格式 定義一個 block 可以實現跨平臺,不僅可以用在web, 還可以用在 Android and iOS。另外 json 格式被設計用來簡化開發時具有不同單詞排序語言的本地化程式,我的理解是阿拉伯語之類的語言是從右往左書寫的,json 能簡單點吧,下面是通過 json 定義一個程式碼塊。

Blockly has two ways of defining blocks: JSON objects and JavaScript functions. The JSON format is cross-platform so that the same code may be used to define blocks on web, Android, and iOS. Additionally, the JSON format is designed to simplify the localization process when developing for languages with different word orderings. The JSON format is the preferred method of defining blocks.

// 通過 json 定義一個程式碼塊
{
  "type": "hello",
  "message0": "輸出 %1",
  "args0": [
    {
      "type": "field_input",
      "name": "say_content",
      "text": "hello world"
    }
  ],
  "inputsInline": true,
  "previousStatement": null,
  "nextStatement": null,
  "colour": 230,
  "tooltip": "",
  "helpUrl": ""
}
複製程式碼

解析自定義 block 為可執行程式碼

定義好了一個 block 是時候看一下它長什麼樣子了,下圖:看起來像積木一樣可以拼接與拖拽。

[blockly 系列] 第 1 篇 環境搭建
此刻從圖中已經可以看明白這個 block 大概要做些什麼事情,但它現在還不是一個程式碼塊,需要我們解析為可執行程式碼來告訴機器,所以緊接著要做的就是寫一段程式碼並匯出,下面這段 js 程式碼在控制檯列印出字串 'hello world'。

// hello 是自定義程式碼塊的名稱
Blockly.JavaScript['hello'] = function (block) {
    this.text_say_content = block.getFieldValue('say_content');
    // TODO: Assemble JavaScript into code variable.
    var code = `console.log(this.text_say_content}`;
    return code;
};
複製程式碼

新增 block 到工具箱 (toolbox)

工具箱類似左側選單欄,代表著一個 block 初始時放在什麼地方,toolbox 以 xml 結構表示,也可以通過 Blockly Developer Tools(視覺化生成 block 與 toolbox 的工具) 工具來生成,先來看看它的結構和怎麼用來包含自定義程式碼塊。

<xml id="toolbox" style="display: none">
    <block type="hello"></block>
</xml>
複製程式碼

生成工作區

生成了 block, toolbox 最後要做的就是把它注入到當前文件的 dom 節點中,通過下面程式碼生成工作區,將 blockly 工具箱注入到 id="blocklyDiv" 的 div 標籤中。

// html
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>

// js
this.demoWorkspace = Blockly.inject('blocklyDiv',  
    {media: './static/media/', toolbox: document.getElementById('toolbox')}
    );
複製程式碼

最終效果

下圖中左側灰色區域展示了工具箱與一個程式碼塊,右側展示了拖拽到工作區的程式碼塊

[blockly 系列] 第 1 篇 環境搭建

獲取合成程式碼

最終的工作區必然是由眾多積木(程式碼塊)搭建而成,雖然栗子中目前只有一個程式碼塊,但不管搭建了多少積木,獲取合成程式碼的方法是一樣的

// latestCode 就是最終合成程式碼
this.latestCode = Blockly.JavaScript.workspaceToCode(this.demoWorkspace);
複製程式碼

做一個演示

給文件新增兩個按鈕和方法,分別用來展示和執行合成的程式碼

[blockly 系列] 第 1 篇 環境搭建

寫在最後

程式碼已上傳到了Github, 可點選檢視效果 blockly-demo, 下一篇將重點介紹自定義程式碼塊與工具箱的生成,以及 Blockly Developer Tools (如果這個連結打不開,請不要懷疑網路和檢查網線,原因你懂得。。。) 工具的使用。

相關文章