擴充功能和更改器

擴充功能是指當指定類型的每個區塊上執行的函式,因為區塊 已建立。這些行為通常會在區塊中加入自訂設定或行為

變數是特殊的擴充功能,可以新增自訂序列化,以及 例如 UI 或 UI

額外資訊

擴充功能是指當指定類型的每個區塊上執行的函式,因為區塊 已建立。他們可能會新增自訂設定 (例如設定區塊的工具提示) 或 自訂行為 (例如在區塊中加入事件監聽器)。

// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
    'parent_tooltip_extension',
    function() { // this refers to the block that the extension is being run on
      var thisBlock = this;
      this.setTooltip(function() {
        var parent = thisBlock.getParent();
        return (parent && parent.getInputsInline() && parent.tooltip) ||
            Blockly.Msg.MATH_NUMBER_TOOLTIP;
      });
    });

擴充功能必須「註冊」這樣就能與字串建立關聯 鍵。接著,您可以將這個字串鍵指派給以下項目的 extensions 屬性: 區塊類型的 JSON 定義,以便套用 新增至區塊

{
 //...,
 "extensions": ["parent_tooltip_extension",]
}

甚至可以一次新增多則額外資訊。請注意,extensions 屬性都必須是陣列,即使您只套用一個副檔名也一樣。

{
  //...,
  "extensions": ["parent_tooltip_extension", "break_warning_extension"],
}

混合

Blockly 也提供便利的方法, 某些屬性/輔助函式新增至區塊,但不會立即執行。這個 方法是讓您可以註冊一組合輯 物件,內含所有額外的屬性/方法。混合物體 然後納入一個函式中,每當 指定區塊類型建立後

Blockly.Extensions.registerMixin('my_mixin', {
  someProperty: 'a cool value',

  someMethod: function() {
    // Do something cool!
  }
))`

與組合相關聯的字串鍵可在 JSON 中參照,就像任何其他鍵一樣 。

{
 //...,
 "extensions": ["my_mixin"],
}

變動器

變動器是一種特殊類型的擴充功能,可新增額外的序列化作業 (額外項目) 儲存和載入的狀態) 至區塊舉例來說 controls_iflist_create_with 區塊需要額外的序列化程序, 可以儲存輸入資料數量

請注意,變更封鎖形狀並不一定表示您需要 額外序列化。舉例來說,math_number_property 區塊 但它取決於下拉式選單欄位 (值已取得) 序列化。因此,您可以使用 欄位 驗證工具 需要變動器

請參閱序列化程序 頁面 或進一步瞭解需要變動器的時機。

如果發生下列情況,變動器也會提供內建 UI,方便使用者變更區塊形狀 您提供一些選用的方法

序列化掛鉤

變異器有兩對序列化掛鉤。一對勾 新的 JSON 序列化系統可以使用,另一對使用 還是傳統的 XML 序列化系統您必須提供至少其中一個組合。

storeExtraState 和 loadExtraState

saveExtraStateloadExtraState 是能與 新的 JSON 序列化系統。saveExtraState 會傳回 JSON 可序列化 值 (表示區塊的額外狀態),而 loadExtraState 值 可接受相同的 JSON 可序列化值,並將其套用至區塊。

// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
  return {
    'itemCount': this.itemCount_,
  };
},

loadExtraState: function(state) {
  this.itemCount_ = state['itemCount'];
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

產生的 JSON 應如下所示:

{
  "type": "lists_create_with",
  "extraState": {
    "itemCount": 3 // or whatever the count is
  }
}
沒有任何狀態

如果區塊處於序列化時的預設狀態,則 saveExtraState 方法可傳回 null 來表示這一點。如果您的 saveExtraState 方法會傳回 null,然後未在當中加入任何 extraState 屬性 例如 JSON這樣可以縮減儲存檔案大小。

完整序列化與備份資料

saveExtraState 也會收到選用的 doFullSerialization 參數。這個 由其他參照狀態的區塊 serializer (例如備份資料模型)。參數會指出 將區塊還原序列化時,系統就無法使用參照狀態,因此 區塊應將所有備份狀態本身序列化。舉例來說 當個別區塊序列化,或複製貼上區塊時,則為 true。

以下是兩個常見用途:

  • 將個別區塊載入備份資料的工作區時 就會產生足夠的資訊 建立新的資料模型
  • 複製貼上區塊時,一律建立新的備份 而非參照現有資料模型

使用這種模式的部分模塊 @blockly/block-shareable-procedures 區塊正常 容器可將參照序列化到備份資料模型,而這些資料模型會儲存其狀態。 但如果 doFullSerialization 參數為 true,則這些函式會將所有 他們的狀態可共用程序區塊,會依據此設定 會建立新的備份資料模型 現有模型

mutationToDom 和 domToMutation

mutationToDomdomToMutation 是能與 還是傳統的 XML 序列化系統請只在必要情況下使用這些掛鉤 (例如 處理尚未遷移的舊程式碼集),或改為使用 《saveExtraState》和《loadExtraState》。

mutationToDom 會傳回一個 XML 節點,代表該節點的額外狀態 區塊,domToMutation接受該 XML 節點並套用狀態 區塊

// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
  // You *must* create a <mutation></mutation> element.
  // This element can have children.
  var container = Blockly.utils.xml.createElement('mutation');
  container.setAttribute('items', this.itemCount_);
  return container;
},

domToMutation: function(xmlElement) {
  this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

產生的 XML 應如下所示:

<block type="lists_create_with">
  <mutation items="3"></mutation>
</block>

如果 mutationToDom 函式傳回空值,就不會有任何多餘元素 加入到 XML 中。

UI 掛勾

如果您為可變動者提供特定函式,Blockly 會在這些函數中加入 預設「變動者」加入區塊的使用者介面

如要新增額外序列化,則不必使用這個 UI。您可以 使用自訂使用者介面,例如從 blocks-plus-減號 外掛程式 或者您可能根本不使用任何使用者介面!

撰寫與分解

預設 UI 會使用 composedecompose 函式。

decompose「爆炸」不妨將方塊分成數個可移動的子區塊 週邊、新增和刪除的事件這個函式應傳回「頂層區塊」這是 子區塊所連線的變動者工作區主要區塊。

compose 接著會解讀子區塊的設定,並用於 修改主區塊這個函式應接受「頂層區塊」那是 decompose 傳回的字串。

請注意,這些函式會「混合」變成「已變更」的區塊所以 this 參照該區塊

// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
  // This is a special sub-block that only gets created in the mutator UI.
  // It acts as our "top block"
  var topBlock = workspace.newBlock('lists_create_with_container');
  topBlock.initSvg();

  // Then we add one sub-block for each item in the list.
  var connection = topBlock.getInput('STACK').connection;
  for (var i = 0; i < this.itemCount_; i++) {
    var itemBlock = workspace.newBlock('lists_create_with_item');
    itemBlock.initSvg();
    connection.connect(itemBlock.previousConnection);
    connection = itemBlock.nextConnection;
  }

  // And finally we have to return the top-block.
  return topBlock;
},

// The container block is the top-block returned by decompose.
compose: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we collect up all of the connections of on our main block that are
  // referenced by our sub-blocks.
  // This relates to the saveConnections hook (explained below).
  var connections = [];
  while (itemBlock && !itemBlock.isInsertionMarker()) {  // Ignore insertion markers!
    connections.push(itemBlock.valueConnection_);
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }

  // Then we disconnect any children where the sub-block associated with that
  // child has been deleted/removed from the stack.
  for (var i = 0; i < this.itemCount_; i++) {
    var connection = this.getInput('ADD' + i).connection.targetConnection;
    if (connection && connections.indexOf(connection) == -1) {
      connection.disconnect();
    }
  }

  // Then we update the shape of our block (removing or adding iputs as necessary).
  // `this` refers to the main block.
  this.itemCount_ = connections.length;
  this.updateShape_();

  // And finally we reconnect any child blocks.
  for (var i = 0; i < this.itemCount_; i++) {
    connections[i].reconnect(this, 'ADD' + i);
  }
},

saveConnections

您也可以視需要定義 saveConnections 函式,以用於 預設 UI這個函式可讓您結合 主要工作區 (位於主要工作區) 含有子區塊,其中包含 變更工具工作區您可以運用這項資料來確保 compose 函式可正確重新連結主要區塊的子項, 子區塊則重新編排。

saveConnections」應接受「頂層封鎖」由您的 decompose 退回 函式做為參數如果已定義 saveConnections 函式,則 Blockly 呼叫 compose 之前。

saveConnections: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we go through and assign references to connections on our main block
  // (input.connection.targetConnection) to properties on our sub blocks
  // (itemBlock.valueConnection_).
  var i = 0;
  while (itemBlock) {
    // `this` refers to the main block (which is being "mutated").
    var input = this.getInput('ADD' + i);
    // This is the important line of this function!
    itemBlock.valueConnection_ = input && input.connection.targetConnection;
    i++;
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }
},

註冊中

變動器是特殊的擴充功能 才能用在區塊類型的 JSON 的定義

// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);

// Example call.
Blockly.Extensions.registerMutator(
    'controls_if_mutator',
    { /* mutator methods */ },
    undefined,
    ['controls_if_elseif', 'controls_if_else']);
  • name:與變動器關聯的字串,可讓您在 JSON 中使用。
  • mixinObj:包含各種異動方法的物件。例如: 《saveExtraState》和《loadExtraState》。
  • opt_helperFn:一種選用的輔助函式,會 混合完成後才會到區塊上測試
  • opt_blockList:這是選用的區塊類型陣列 (為字串),之後會 新增至預設切換器 UI (如果 UI 方法也包含)

請注意,與擴充功能不同,每個區塊類型只能有一個可變動者。

{
  //...
  "mutator": "controls_if_mutator"
}

輔助函式

除了混合,變因器也可以註冊輔助函式。這個函式 系統就會在建立指定類型後,對該類型的每個區塊執行 已新增。可用來在變動中加入額外的觸發條件或效果。

舉例來說,您可以將輔助程式新增至類似清單的區塊 初始項目數量:

var helper = function() {
  this.itemCount_ = 5;
  this.updateShape();
}