ก่อนสร้างประเภทช่องใหม่ ให้พิจารณาดูว่ามีวิธีอื่นๆ ในการปรับแต่งช่องให้เหมาะกับความต้องการของคุณหรือไม่ หากแอปพลิเคชันของคุณจำเป็นต้องจัดเก็บประเภทค่าใหม่ หรือคุณต้องการสร้าง UI ใหม่สำหรับประเภทค่าที่มีอยู่ คุณอาจต้องสร้างประเภทช่องใหม่
วิธีสร้างฟิลด์ใหม่มีดังนี้
- ใช้ตัวสร้าง
- ลงทะเบียนคีย์ JSON และใช้
fromJson
- จัดการการเริ่มต้น UI ที่บล็อกไว้และผู้ฟังเหตุการณ์
- จัดการการกำจัด Listener เหตุการณ์ (การกำจัด UI ให้คุณ)
- ใช้การจัดการมูลค่า
- เพิ่มการแสดงข้อความสำหรับค่าของช่องสำหรับการช่วยเหลือพิเศษ
- เพิ่มฟังก์ชันการทำงานอื่นๆ เช่น
- กำหนดค่าแง่มุมเพิ่มเติมของช่อง เช่น
ในส่วนนี้จะถือว่าคุณได้อ่านและคุ้นเคยกับเนื้อหาในโครงสร้างของช่องแล้ว
ดูตัวอย่างของช่องที่กำหนดเองได้ในการสาธิตช่องที่กำหนดเอง
การติดตั้งตัวสร้าง
ตัวสร้างของช่องมีหน้าที่ในการตั้งค่าเริ่มต้นของฟิลด์ และตั้งค่าเครื่องมือตรวจสอบภายใน (ไม่บังคับ) ระบบจะเรียกตัวสร้างของช่องที่กำหนดเองระหว่างการเริ่มต้นบล็อกแหล่งที่มา ไม่ว่าจะกำหนดบล็อกแหล่งที่มาไว้ใน JSON หรือ JavaScript ก็ตาม ดังนั้น ช่องที่กำหนดเองจึงไม่มีสิทธิ์เข้าถึงบล็อกแหล่งที่มาระหว่างการสร้าง
ตัวอย่างโค้ดต่อไปนี้จะสร้างฟิลด์ที่กำหนดเองชื่อ GenericField
:
class GenericField extends Blockly.Field {
constructor(value, validator) {
super(value, validator);
this.SERIALIZABLE = true;
}
}
ลายเซ็นเมธอด
โดยปกติแล้วตัวสร้างฟิลด์จะใช้ค่าและเครื่องมือตรวจสอบภายใน ค่านี้จะเป็นแบบไม่บังคับและหากคุณไม่ส่งค่า (หรือคุณส่งค่าที่ไม่ผ่านการตรวจสอบคลาส) ระบบจะใช้ค่าเริ่มต้นของซูเปอร์คลาส สำหรับคลาส Field
เริ่มต้น ค่านี้คือ null
หากไม่ต้องการค่าเริ่มต้นนั้น
อย่าลืมส่งค่าที่เหมาะสม พารามิเตอร์โปรแกรมตรวจสอบจะปรากฏ
สำหรับช่องที่แก้ไขได้และมักจะทำเครื่องหมายว่าไม่บังคับ ดูข้อมูลเพิ่มเติม
เกี่ยวกับโปรแกรมตรวจสอบได้ในเอกสาร
ผู้ตรวจสอบ
โครงสร้าง
ตรรกะภายในตัวสร้างควรเป็นไปตามขั้นตอนนี้
- เรียกใช้ตัวสร้างระดับสูงที่รับช่วงมา (ช่องที่กำหนดเองทั้งหมดควรรับค่าจาก
Blockly.Field
หรือคลาสย่อย) เพื่อเริ่มต้นค่าอย่างถูกต้องและตั้งค่าโปรแกรมตรวจสอบภายในสำหรับฟิลด์ของคุณ - หากช่องทำให้เป็นอนุกรมได้ ให้ตั้งค่าพร็อพเพอร์ตี้ที่สอดคล้องกันในตัวสร้าง ช่องที่แก้ไขได้จะต้องเป็นแบบทำให้เป็นอนุกรมได้ และช่องดังกล่าวจะแก้ไขได้โดยค่าเริ่มต้น คุณจึงควรตั้งค่าพร็อพเพอร์ตี้นี้เป็น "จริง" เว้นแต่คุณจะทราบว่าไม่ควรทำให้เป็นอนุกรมได้
- ไม่บังคับ: ใช้การปรับแต่งเพิ่มเติม (เช่น ช่องป้ายกำกับทำให้สามารถส่งคลาส CSS ซึ่งจากนั้นจะนำไปใช้กับข้อความ)
JSON และการลงทะเบียน
ในการกำหนดบล็อก JSON ช่องจะอธิบายด้วยสตริง (เช่น field_number
, field_textinput
)
บล็อกจะดูแลแผนที่จากสตริงเหล่านี้ไปยังออบเจ็กต์ในช่อง และเรียกใช้fromJson
บนออบเจ็กต์ที่เหมาะสมระหว่างการสร้าง
เรียก Blockly.fieldRegistry.register
เพื่อเพิ่มประเภทฟิลด์ลงในแมปนี้
โดยส่งเป็นอาร์กิวเมนต์ที่ 2 ในคลาสฟิลด์:
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
หากคุณต้องการให้ช่องมีทั้ง 2 อย่างนี้ รวมถึงสินค้าพิเศษ ให้เรียกใช้ฟังก์ชัน initView
ใน Superclass ก่อนเพิ่มองค์ประกอบ DOM ที่เหลือ หากต้องการให้ช่องมีองค์ประกอบ 1 รายการ แต่ไม่ใช่ทั้ง 2 องค์ประกอบ ให้ใช้ฟังก์ชัน createBorderRect_
หรือ createTextElement_
การปรับแต่งการสร้าง DOM
หากช่องของคุณเป็นช่องข้อความทั่วไป (เช่น อินพุตข้อความ) เราจะจัดการการสร้าง DOM ให้คุณ ไม่เช่นนั้น คุณจะต้องลบล้างฟังก์ชัน initView
เพื่อสร้างองค์ประกอบ DOM ที่ต้องใช้ในระหว่างการแสดงผลช่องในอนาคต
เช่น ช่องแบบเลื่อนลงอาจมีทั้งรูปภาพและข้อความ ใน initView
ระบบจะสร้างองค์ประกอบรูปภาพรายการเดียวและองค์ประกอบข้อความรายการเดียว จากนั้นในช่วง render_
องค์ประกอบนั้นจะแสดงองค์ประกอบที่ใช้งานอยู่และซ่อนอีกองค์ประกอบหนึ่งไว้โดยอิงตามประเภทของตัวเลือกที่เลือก
คุณสร้างองค์ประกอบ DOM โดยใช้เมธอด Blockly.utils.dom.createSvgElement
หรือวิธีสร้าง DOM แบบดั้งเดิมก็ได้
ข้อกำหนดของการแสดงช่องในบล็อกมีดังนี้
- องค์ประกอบ DOM ทั้งหมดต้องเป็นรายการย่อยของ
fieldGroup_
ของช่อง ระบบจะสร้างกลุ่ม ฟิลด์โดยอัตโนมัติ - องค์ประกอบ DOM ทั้งหมดต้องอยู่ภายในขนาดที่รายงานของช่อง
ดูรายละเอียดเพิ่มเติมเกี่ยวกับการปรับแต่งและอัปเดตการแสดงผลเมื่อบล็อกในส่วนการแสดงผล
การเพิ่มสัญลักษณ์ข้อความ
หากต้องการเพิ่มสัญลักษณ์ในข้อความของช่อง (เช่น สัญลักษณ์องศาของมุมของช่อง) คุณสามารถเพิ่มองค์ประกอบสัญลักษณ์ (โดยปกติจะมีอยู่ใน <tspan>
) ต่อท้าย textElement_
ของช่องได้โดยตรง
เหตุการณ์การป้อนข้อมูล
โดยค่าเริ่มต้น ช่องจะลงทะเบียนเหตุการณ์เคล็ดลับเครื่องมือและเหตุการณ์เมาส์ดาวน์ (ใช้เพื่อแสดงเครื่องมือแก้ไข)
หากต้องการฟังเหตุการณ์ประเภทอื่นๆ (เช่น หากต้องการจัดการการลากในช่อง) คุณควรลบล้างฟังก์ชัน 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
ได้
การกำจัด
หากลงทะเบียน Listener เหตุการณ์ที่กำหนดเองภายในฟังก์ชัน 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
และลบล้างการแสดงผล_ เพื่อให้การแสดงผลในบล็อกอัปเดตตาม 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
แทนการตรวจสอบพร็อพเพอร์ตี้แต่ละรายการอีกครั้ง
รูปแบบสำหรับการตรวจสอบค่าที่มีหลายส่วนนี้ยังใช้ได้ในโปรแกรมตรวจสอบในเครื่องด้วย แต่ขณะนี้ยังไม่มีวิธีบังคับใช้รูปแบบนี้
isDirty_
isDirty_
คือแฟล็กที่ใช้ในฟังก์ชัน setValue
และส่วนอื่นๆ ของช่อง เพื่อบอกว่าต้องแสดงผลช่องอีกครั้งหรือไม่ หากค่าการแสดงผลของช่องมีการเปลี่ยนแปลง โดยปกติแล้วควรตั้งค่า isDirty_
เป็น true
ข้อความ
→ สำหรับข้อมูลเกี่ยวกับตำแหน่งที่ใช้ข้อความของช่องและความแตกต่างกับค่าของช่อง โปรดดูที่การวิเคราะห์ช่อง
หากข้อความในช่องแตกต่างจากค่าของช่อง คุณควรลบล้างฟังก์ชัน 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 ใดๆ ในโปรแกรมแก้ไขของคุณได้โดยการรวม Div พิเศษ 1 จาก 2 รายการที่เรียกว่า DropDownDiv และ WidgetDiv ซึ่งลอยเหนือ UI ที่เหลือของ 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 ของวิดเจ็ต แต่คุณต้องกำจัด Listener เหตุการณ์ที่คุณใช้กับองค์ประกอบเหล่านั้นด้วยตนเอง
widgetDispose_() {
for (let i = this.editorListeners_.length, listener;
listener = this.editorListeners_[i]; i--) {
Blockly.browserEvents.unbind(listener);
this.editorListeners_.pop();
}
}
ระบบจะเรียกใช้ฟังก์ชัน dispose
ในบริบท null
ใน DropDownDiv
ใน WidgetDiv
ระบบจะเรียกใช้ URL นี้ในบริบทของ WidgetDiv
ไม่ว่ากรณีใด ก็ควรใช้ฟังก์ชัน bind เมื่อส่งฟังก์ชันการกำจัด ดังที่แสดงในตัวอย่าง DropDownDiv
และ WidgetDiv
ด้านบน
→ สำหรับข้อมูลเกี่ยวกับการกำจัดไฟล์ที่ไม่ได้มีไว้สำหรับการกำจัดเอดิเตอร์โดยเฉพาะ โปรดดูการกำจัด
กำลังอัปเดตจอแสดงผลในบล็อก
ใช้ฟังก์ชัน render_
เพื่ออัปเดตการแสดงผลบนบล็อกของช่องให้ตรงกับค่าภายใน
ตัวอย่างทั่วไปมีดังนี้
- เปลี่ยนข้อความ (เมนูแบบเลื่อนลง)
- เปลี่ยนสี (สี)
ค่าเริ่มต้น
ฟังก์ชัน render_
เริ่มต้นจะตั้งค่าข้อความที่แสดงตามผลลัพธ์ของฟังก์ชัน getDisplayText_
ฟังก์ชัน getDisplayText_
จะแสดงผลพร็อพเพอร์ตี้ value_
ของช่องที่แคสต์ไปยังสตริง หลังจากที่มีการตัดข้อความตามความยาวสูงสุดของข้อความ
หากคุณใช้การแสดงในบล็อกที่เป็นค่าเริ่มต้นและลักษณะการทำงานของข้อความเริ่มต้นมีผลกับช่องของคุณ คุณก็ไม่จำเป็นต้องลบล้าง render_
หากการทำงานของข้อความเริ่มต้นใช้ได้กับช่องของคุณ แต่หน้าจอบนบล็อกของช่องมีองค์ประกอบแบบคงที่เพิ่มเติม คุณจะเรียกใช้ฟังก์ชัน render_
เริ่มต้นได้ แต่คุณยังคงต้องลบล้างเพื่ออัปเดตขนาดของช่อง
หากการทำงานของข้อความเริ่มต้นใช้ไม่ได้กับช่องของคุณ หรือหน้าจอบนบล็อกของช่องมีองค์ประกอบแบบไดนามิกเพิ่มเติม คุณจะต้องปรับแต่งฟังก์ชัน render_
การปรับแต่งการแสดงผล
หากลักษณะการแสดงผลเริ่มต้นใช้ไม่ได้กับช่องของคุณ คุณจะต้องกำหนดลักษณะการแสดงผลที่กำหนดเอง ไม่ว่าจะเป็นการตั้งค่าข้อความที่แสดงที่กำหนดเอง การเปลี่ยนองค์ประกอบรูปภาพ ไปจนถึงการอัปเดตสีพื้นหลัง
การเปลี่ยนแปลงแอตทริบิวต์ DOM ทั้งหมดเป็นสิ่งที่ถูกกฎหมาย มีอยู่ 2 สิ่งที่ต้องจดจำคือ:
- คุณควรจัดการการสร้าง DOM ในระหว่างการเริ่มต้นใช้งาน เนื่องจากวิธีนี้มีประสิทธิภาพมากกว่า
- คุณควรอัปเดตพร็อพเพอร์ตี้
size_
ให้ตรงกับขนาดโฆษณาแบบดิสเพลย์ที่ใช้บล็อกเสมอ
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 มีฮุกอนุกรม 2 ชุดสำหรับช่องต่างๆ ฮุกคู่หนึ่งใช้งานได้กับระบบอนุกรม JSON ใหม่ ส่วนอีกคู่หนึ่งใช้งานได้กับระบบการเรียงลำดับ XML แบบเก่า
saveState
และloadState
saveState
และ loadState
คือฮุกอนุกรมที่ใช้งานได้กับระบบการทำให้เป็นอนุกรม JSON ใหม่
ในบางกรณีคุณไม่จำเป็นต้องระบุรายการเหล่านี้เนื่องจากการติดตั้งใช้งานเริ่มต้นจะใช้ได้ หาก (1) ช่องเป็นคลาสย่อยโดยตรงของคลาส Blockly.Field
พื้นฐาน (2) ค่าเป็นประเภทการทำให้เป็นอนุกรม JSON และ (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
ด้วย ช่องนี้ใช้โดยช่องที่โดยปกติจะอ้างอิงสถานะที่ทำให้เป็นอนุกรมโดยซีเรียลไลเซอร์อื่น (เช่น การสำรองข้อมูลโมเดลข้อมูล) สัญญาณพารามิเตอร์ที่สถานะที่อ้างอิงจะไม่สามารถใช้งานได้เมื่อบล็อกได้รับการดีซีเรียลไลซ์ ช่องจึงควรทำการเรียงลำดับทั้งหมดด้วยตนเอง ตัวอย่างเช่น กรณีนี้จะเกิดขึ้นเมื่อมีการทำให้บล็อกหนึ่งๆ เป็นอนุกรม หรือเมื่อมีการคัดลอกและวางบล็อก
กรณีการใช้งานทั่วไปสำหรับกรณีนี้มี 2 กรณีดังนี้
- เมื่อมีการโหลดแต่ละบล็อกเข้าไปในพื้นที่ทำงานที่ไม่มีโมเดลข้อมูลสนับสนุนอยู่ ช่องนี้จะมีข้อมูลในสถานะของตัวเองเพียงพอที่จะสร้างโมเดลข้อมูลใหม่
- เมื่อมีการคัดลอกและวางบล็อก ช่องนี้จะสร้างโมเดลข้อมูลสนับสนุนใหม่เสมอแทนที่จะอ้างอิงโมเดลที่มีอยู่
ช่องหนึ่งที่ใช้ช่องนี้คือช่องตัวแปรบิวท์อิน โดยปกติจะทำให้รหัสของตัวแปรที่อ้างอิงอยู่เป็นอนุกรม แต่หาก doFullSerialization
เป็นจริง จะทำให้ทุกสถานะเป็นอนุกรม
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 แบบเก่า ใช้ hook เหล่านี้เมื่อจำเป็นเท่านั้น (เช่น คุณกำลังสร้างฐานโค้ดเก่าที่ยังไม่ได้ย้ายข้อมูล) มิฉะนั้น ให้ใช้ 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
ซึ่งก็คือเคอร์เซอร์จับ