建立新的欄位類型之前,請先評估其中是否含有其他欄位 方法 來自訂欄位。如果您的應用程式需要儲存 或者想為現有值類型建立新的 UI 可能需要建立新的欄位類型
如要建立新欄位,請執行下列步驟:
- 實作建構函式。
- 註冊 JSON 金鑰並實作
fromJson
。 - 處理區塊端 UI 和事件的初始化作業 接聽程式。
- 處理事件監聽器的處理 (系統會針對 您)。
- 實作價值處理。
- 新增欄位值的文字表示法,方便無障礙功能。
- 新增額外功能,例如:
- 設定欄位的其他方面,例如:
本節假設您已閱讀並熟悉 剖析 欄位。
如需自訂欄位的範例,請參閱「自訂欄位」 示範 ,直接在 Google Cloud 控制台實際操作。
實作建構函式
欄位的建構函式負責設定欄位的初始值 並視需要將本地設定 驗證工具。自訂範本 欄位的建構函式會在來源區塊初始化期間呼叫,無論如何 顯示來源區塊是以 JSON 或 JavaScript 定義。自訂工作是由 欄位的建立期間無法存取來源區塊。
下列程式碼範例會建立名為 GenericField
的自訂欄位:
class GenericField extends Blockly.Field {
constructor(value, validator) {
super(value, validator);
this.SERIALIZABLE = true;
}
}
方法簽章
欄位建構函式通常會採用值和本機驗證工具。值為
要是您未傳遞值 (或傳遞類別失敗的值)
驗證),那麼會使用父類別的預設值。對於
預設的 Field
類別,值為 null
。如果不想要使用預設選項
值,請務必傳送合適的值。驗證工具參數
會顯示於可編輯欄位,且通常會標示為「選填」。瞭解詳情
驗證工具中的驗證工具
文件。
結構
建構函式中的邏輯應遵循以下流程:
- 呼叫沿用的超建構函式 (所有自訂欄位均應沿用
Blockly.Field
或其其中一個子類別),以便正確初始化該值 並為該欄位設定本機驗證工具 - 如果欄位可以序列化,請在 建構函式中設定。可編輯的欄位必須可序列化,且欄位可以編輯 所以您應該將這個屬性設為 true,除非您知道 則不應可序列化
- 選用:套用其他自訂項目 (例如標籤欄位)。 允許傳送 css 類別,並套用至文字)。
JSON 與登錄
在「JSON 區塊」
定義、
欄位是以字串 (例如 field_number
、field_textinput
) 表示。
Blockly 會維護來自這些字串到欄位物件的對應,以及
建構期間在適當物件的 fromJson
上。
呼叫 Blockly.fieldRegistry.register
即可將欄位類型加入此地圖。
傳入欄位類別做為第二個引數:
Blockly.fieldRegistry.register('field_generic', GenericField);
您也需要定義 fromJson
函式。實作項目
先解除參照任何 字串
表格
參照的
replaceMessageReferences,
然後將值傳遞至建構函式。
GenericField.fromJson = function(options) {
const value = Blockly.utils.parsing.replaceMessageReferences(
options['value']);
return new CustomFields.GenericField(value);
};
正在初始化
建立欄位時,欄位基本上只包含一個值。 初始化是建構 DOM 的位置,會建立模型 (如果欄位有 擁有模型),而事件則會繫結。
螢幕長亮模式
在初始化期間,您必須負責建立所需的任何內容 以便讓欄位在區塊上顯示
預設、背景和文字
預設的 initView
函式會建立淺色的 rect
元素和
text
元素。如果希望欄位同時包含這兩個欄位,加上一些額外值
等人,請先呼叫父類別 initView
函式,然後再新增其餘的
DOM 元素如果您希望欄位只加入一個欄位,但不要同時加入兩者,
可使用 createBorderRect_
或 createTextElement_
函式。
自訂 DOM 建構
如果您的欄位是一般文字欄位 (例如「Text」
Input)
系統會為您處理 DOM 建構程序。否則,您就必須
initView
函式建立需要用到的 DOM 元素
以便日後轉譯欄位。
例如,下拉式選單欄位可能包含圖片和文字。initView
內
可建立單一圖片元素和單一文字元素。之後render_
會根據
您可使用
Blockly.utils.dom.createSvgElement
方法或使用傳統 DOM 建立功能
方法。
欄位的區塊顯示螢幕適用以下規定:
- 所有 DOM 元素都必須是該欄位
fieldGroup_
的子項。欄位 即可自動建立群組。 - 所有 DOM 元素都必須保持在欄位回報的尺寸之內。
詳情請參閱 轉譯 一節,進一步瞭解如何自訂及更新顯示器畫面。
新增文字符號
如何在欄位文字中加入符號 (例如
角度
] 欄位的度數符號),即可附加符號元素 (通常包含在
<tspan>
) 直接加入欄位的 textElement_
。
輸入事件
根據預設,欄位會登錄工具提示事件,以及滑鼠指向事件 (用於
顯示
editors)。
監聽其他類型的事件 (例如想處理
拖曳欄位),就應該覆寫該欄位的 bindEvents_
函式。
bindEvents_() {
// Call the superclass function to preserve the default behavior as well.
super.bindEvents_();
// Then register your own additional event listeners.
this.mouseDownWrapper_ =
Blockly.browserEvents.conditionalBind(this.getClickTarget_(), 'mousedown', this,
function(event) {
this.originalMouseX_ = event.clientX;
this.isMouseDown_ = true;
this.originalValue_ = this.getValue();
event.stopPropagation();
}
);
this.mouseMoveWrapper_ =
Blockly.browserEvents.conditionalBind(document, 'mousemove', this,
function(event) {
if (!this.isMouseDown_) {
return;
}
var delta = event.clientX - this.originalMouseX_;
this.setValue(this.originalValue_ + delta);
}
);
this.mouseUpWrapper_ =
Blockly.browserEvents.conditionalBind(document, 'mouseup', this,
function(_event) {
this.isMouseDown_ = false;
}
);
}
如要繫結至事件,通常應該使用
Blockly.utils.browserEvents.conditionalBind
敬上
函式。這種繫結事件方法會在期間篩除次要輕觸動作
。如果您希望處理常式即使在進行中的拖曳過程中也可執行
您可以使用
Blockly.browserEvents.bind
敬上
函式。
丟棄
如果您在欄位的 bindEvents_
中註冊任何自訂事件監聽器
您需要在 dispose
函式中取消註冊。
如果您正確初始化
檢視畫面
(透過將所有 DOM 元素附加至 fieldGroup_
後),
欄位的 DOM 會自動處理。
價值處理
→ 如要瞭解欄位值與其文字的相關資訊,請參閱「剖析 欄位。
驗證順序
實作類別驗證工具
欄位只接受特定值。舉例來說,數字欄位 接受數字,顏色欄位應只接受顏色等。 透過類別和地方 驗證工具。課程 驗證工具遵循與本機驗證相同的規則,差別在於驗證工具也會執行 的 建構函式 因此,不應參照來源區塊。
如要實作欄位的類別驗證工具,請覆寫 doClassValidation_
函式。
doClassValidation_(newValue) {
if (typeof newValue != 'string') {
return null;
}
return newValue;
};
處理有效值
如果傳遞至具有 setValue
欄位的值有效,您會收到
doValueUpdate_
回呼。根據預設,doValueUpdate_
函式:
- 將
value_
屬性設為newValue
。 - 設定
isDirty_
設為true
如果您只需要儲存值,且不想執行任何自訂處理方式
不需要覆寫 doValueUpdate_
或者,如果您想執行下列操作:
newValue
的自訂儲存空間。- 根據
newValue
變更其他屬性。 - 儲存目前的值是否有效。
您必須覆寫 doValueUpdate_
:
doValueUpdate_(newValue) {
super.doValueUpdate_(newValue);
this.displayValue_ = newValue;
this.isValueValid_ = true;
}
處理無效值
如果傳遞至 setValue
欄位的值無效,您會收到
doValueInvalid_
回呼。根據預設,doValueInvalid_
函式會執行以下動作:
什麼都不做。也就是說,根據預設,無效值不會顯示。此外,
表示系統不會重新轉譯欄位,因為
isDirty_
敬上
資源不會設定。
如要顯示無效的值,請覆寫 doValueInvalid_
。
在多數情況下,您應將 displayValue_
屬性設為
無效的值,請設定
isDirty_
設為 true
,並覆寫
render_
根據 displayValue_
而非
value_
。
doValueInvalid_(newValue) {
this.displayValue_ = newValue;
this.isDirty_ = true;
this.isValueValid_ = false;
}
多部分值
如果您的欄位含有多部分的值 (例如清單、向量、物件), 某些部分可能會像個別值一樣處理。
doClassValidation_(newValue) {
if (FieldTurtle.PATTERNS.indexOf(newValue.pattern) == -1) {
newValue.pattern = null;
}
if (FieldTurtle.HATS.indexOf(newValue.hat) == -1) {
newValue.hat = null;
}
if (FieldTurtle.NAMES.indexOf(newValue.turtleName) == -1) {
newValue.turtleName = null;
}
if (!newValue.pattern || !newValue.hat || !newValue.turtleName) {
this.cachedValidatedValue_ = newValue;
return null;
}
return newValue;
}
在上述範例中,系統會分別驗證 newValue
的每個屬性。接著
如有任何個別屬性,則位於 doClassValidation_
函式結尾
無效,值就會快取至 cacheValidatedValue_
屬性,
傳回 null
(無效)。透過個別驗證的方式快取物件
屬性可讓
doValueInvalid_
敬上
函式並分別處理
!this.cacheValidatedValue_.property
檢查,而不是重新驗證每個
管理個別資源
這種模式也可用於驗證多部分值,不過可用於 local 驗證工具 但無法強制執行這個模式
isDirty_
isDirty_
是
setValue
函式和欄位其他部分,藉此判斷該欄位是否需要
重新轉譯。如果欄位的顯示值有所變更,通常 isDirty_
應該
設為 true
。
文字
→ 瞭解欄位文字的用途以及不同之處 傳回該欄位值,請參閱 Anatomy of a 欄位。
如果欄位文字與欄位的值不同,
覆寫
getText
函式
以便提供正確的文字
getText() {
let text = this.value_.turtleName + ' wearing a ' + this.value_.hat;
if (this.value_.hat == 'Stovepipe' || this.value_.hat == 'Propeller') {
text += ' hat';
}
return text;
}
建立編輯者
如果您定義了 showEditor_
函式,Blockly 會自動監聽
點擊並呼叫 showEditor_
。您可以將任何 HTML
,方法是使用 DropDownDiv 這個特殊 div 功能
和 WidgetDiv,疊加在 Blockly 的使用者介面上方。
DropDownDiv 與 WidgetDiv
DropDownDiv
的用途是提供位於連接方塊中的編輯器
附加至欄位它會自動放置於靠近球場的位置,同時還自動
在可見範圍內角度挑選器和顏色挑選器是絕佳的
DropDownDiv
。
WidgetDiv
的用途是
讓編輯人員以外的編輯作業數字欄位會使用
WidgetDiv 納入內含 HTML 文字輸入框的欄位。DropdownDiv 時
會為您處理定位,WidgetDiv 不會。元素必須
座標系統採用相對於
視窗左上角。文字輸入編輯器是
WidgetDiv
。
DropDownDiv 程式碼範例
showEditor_() {
// Create the widget HTML
this.editor_ = this.dropdownCreate_();
Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_);
// Set the dropdown's background colour.
// This can be used to make it match the colour of the field.
Blockly.DropDownDiv.setColour('white', 'silver');
// Show it next to the field. Always pass a dispose function.
Blockly.DropDownDiv.showPositionedByField(
this, this.disposeWidget_.bind(this));
}
WidgetDiv 程式碼範例
showEditor_() {
// Show the div. This automatically closes the dropdown if it is open.
// Always pass a dispose function.
Blockly.WidgetDiv.show(
this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));
// Create the widget HTML.
var widget = this.createWidget_();
Blockly.WidgetDiv.getDiv().appendChild(widget);
}
清除所用資源
DropDownDiv 和 WidgetDiv 會刪除小工具 HTML 元素,但您必須手動處理 已套用至這些元素
widgetDispose_() {
for (let i = this.editorListeners_.length, listener;
listener = this.editorListeners_[i]; i--) {
Blockly.browserEvents.unbind(listener);
this.editorListeners_.pop();
}
}
系統會在 DropDownDiv
的 null
結構定義中呼叫 dispose
函式。啟用
在 WidgetDiv
結構定義中呼叫的 WidgetDiv
。無論是哪種情況
建議您使用
bind
函式傳遞時的函式,如上述 DropDownDiv
所示
和 WidgetDiv
範例
→ 如要瞭解非特定丟棄編輯者的資訊,請參閱 處理。
更新遮蔽式顯示器
render_
函式可用來更新欄位的螢幕上顯示設定,使其相符
設定本身的內部值
常見的例子包括:
- 更改文字 (下拉式選單)
- 變更顏色 (顏色)
預設值
預設的 render_
函式會將顯示文字設為
getDisplayText_
函式。getDisplayText_
函式會傳回欄位的 value_
屬性
轉換為字串,但截斷以符合文字數量上限
長度。
如果你使用預設的封鎖式顯示畫面和預設文字行為
適用於您的欄位,不需要覆寫 render_
。
如果預設文字行為適用於您的欄位,但欄位的封鎖設定
螢幕含有其他靜態元素,您可以呼叫預設的 render_
函式,但您仍需覆寫這個欄位,才能更新欄位的
大小)。
如果預設文字行為不適用於您的欄位或欄位的
封鎖顯示螢幕具有其他動態元素,您必須自訂
render_
函式。
自訂顯示
如果預設的顯示行為不適用於您的欄位,您需要 定義自訂顯示行為這可能涉及任何設定 例如顯示文字、變更圖片元素,以及更新背景色彩
所有 DOM 屬性變更都是合法的,只有以下兩點需要注意:
render_() {
switch(this.value_.hat) {
case 'Stovepipe':
this.stovepipe_.style.display = '';
break;
case 'Crown':
this.crown_.style.display = '';
break;
case 'Mask':
this.mask_.style.display = '';
break;
case 'Propeller':
this.propeller_.style.display = '';
break;
case 'Fedora':
this.fedora_.style.display = '';
break;
}
switch(this.value_.pattern) {
case 'Dots':
this.shellPattern_.setAttribute('fill', 'url(#polkadots)');
break;
case 'Stripes':
this.shellPattern_.setAttribute('fill', 'url(#stripes)');
break;
case 'Hexagons':
this.shellPattern_.setAttribute('fill', 'url(#hexagons)');
break;
}
this.textContent_.nodeValue = this.value_.turtleName;
this.updateSize_();
}
正在更新大小
更新欄位的 size_
屬性非常重要,因為這樣能通知
區塊轉譯程式碼
說明如何放置欄位相信
確切來說,size_
應該透過實驗來達到目的。
updateSize_() {
const bbox = this.movableGroup_.getBBox();
let width = bbox.width;
let height = bbox.height;
if (this.borderRect_) {
width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
this.borderRect_.setAttribute('width', width);
this.borderRect_.setAttribute('height', height);
}
// Note how both the width and the height can be dynamic.
this.size_.width = width;
this.size_.height = height;
}
比對區塊顏色
如果您希望欄位元素與區塊的色彩相符
您應該覆寫 applyColour
方法。建議你
透過區塊的樣式屬性存取色彩。
applyColour() {
const sourceBlock = this.sourceBlock_;
if (sourceBlock.isShadow()) {
this.arrow_.style.fill = sourceBlock.style.colourSecondary;
} else {
this.arrow_.style.fill = sourceBlock.style.colourPrimary;
}
}
正在更新編輯權限
updateEditable
函式可用於變更欄位的顯示方式
看看是否可以編輯根據預設,這個函式會讓
如果背景無法/無法編輯,則背景不會提供懸停回應 (邊框)。
網上螢幕的可編輯性不應隨大小而改變,
但允許其他變更
updateEditable() {
if (!this.fieldGroup_) {
// Not initialized yet.
return;
}
super.updateEditable();
const group = this.getClickTarget_();
if (!this.isCurrentlyEditable()) {
group.style.cursor = 'not-allowed';
} else {
group.style.cursor = this.CURSOR;
}
}
序列化
序列化的作用是儲存 欄位狀態,方便之後重新載入至工作區。
工作區狀態一律會包含欄位值,但也可能 包含其他狀態,例如欄位的 UI 狀態。舉例來說 欄位是可縮放的地圖,可供使用者選取國家/地區 也可以將縮放等級序列化
如果欄位可序列化,您必須將 SERIALIZABLE
屬性設為
true
。
Blockly 為欄位提供兩組序列化掛鉤。一對勾 新的 JSON 序列化系統可以使用,另一對使用 還是傳統的 XML 序列化系統
saveState
和loadState
saveState
和 loadState
是能與新 JSON 搭配使用的序列化掛鉤
序列化系統。
在某些情況下,您不需要提供這些資訊,
實作程序如果 (1) 您的欄位是基礎子類別的直接子類別
Blockly.Field
類別,(2) 您的值是 JSON 可序列化
type 以及 (3) 您只需要
序列化這個值,那麼預設的實作方式就沒有問題!
否則,saveState
函式應傳回 JSON 可序列化
代表欄位狀態的物件/值。你的loadState
函式應接受相同的 JSON 可序列化物件/值,並套用至
這個欄位。
saveState() {
return {
'country': this.getValue(), // Value state
'zoom': this.getZoomLevel(), // UI state
};
}
loadState(state) {
this.setValue(state['country']);
this.setZoomLevel(state['zoom']);
}
完整序列化與備份資料
saveState
也會收到選用參數 doFullSerialization
。這是
通常參照狀態由不同的
serializer (例如備份資料模型)。參數會指出
將區塊還原序列化時,系統就無法使用參照狀態,因此
欄位應執行所有序列化作業。舉例來說
個別區塊序列化,或複製貼上區塊。
以下是兩個常見用途:
- 將個別區塊載入備份資料的工作區時 則該欄位在自身狀態下擁有足夠的資訊, 建立新的資料模型
- 當您複製區塊時,該欄位一律會建立新的備份 而非參照現有資料模型
使用這個欄位的欄位是內建變數欄位。一般情況下
參照的變數 ID;如果 doFullSerialization
為 true
容器會將所有狀態序列化
saveState(doFullSerialization) {
const state = {'id': this.variable_.getId()};
if (doFullSerialization) {
state['name'] = this.variable_.name;
state['type'] = this.variable_.type;
}
return state;
}
loadState(state) {
const variable = Blockly.Variables.getOrCreateVariablePackage(
this.getSourceBlock().workspace,
state['id'],
state['name'], // May not exist.
state['type']); // May not exist.
this.setValue(variable.getId());
}
這麼做是為了確保變數欄位能載入工作區 只要變數不存在,就能建立一個參照的新變數。
toXml
和fromXml
toXml
和 fromXml
是能與舊版 XML 搭配使用的序列化掛鉤
序列化系統。請只在必要情況下使用這些掛鉤 (例如,在專案
位於尚未遷移的舊程式碼集上),否則請使用 saveState
和
loadState
。
toXml
函式應傳回一個 XML 節點,代表
這個欄位。且 fromXml
函式應接受相同的 XML 節點,並套用
加到欄位中
toXml(fieldElement) {
fieldElement.textContent = this.getValue();
fieldElement.setAttribute('zoom', this.getZoomLevel());
return fieldElement;
}
fromXml(fieldElement) {
this.setValue(fieldElement.textContent);
this.setZoomLevel(fieldElement.getAttribute('zoom'));
}
可編輯與可序列化屬性
EDITABLE
屬性會決定欄位是否應有 UI 來指出
可與之互動預設值為 true
。
SERIALIZABLE
屬性會決定是否應序列化欄位。這項服務
預設值為 false
。如果這個屬性是 true
,您可能需要提供
序列化與去序列化函式 (請參閱
序列化)。
自訂遊標
CURSOR
屬性決定使用者將遊標懸停在上方時看到的遊標。
這個欄位。必須是有效的 CSS 遊標字串。這會預設為遊標
由 .blocklyDraggable
定義,也就是擷取遊標。