ก่อนสร้างประเภทช่องใหม่ ให้พิจารณาว่าวิธีการอื่นๆ สำหรับการปรับแต่งช่องใดที่เหมาะกับความต้องการของคุณ หากแอปพลิเคชันต้องจัดเก็บประเภทค่าใหม่ หรือคุณต้องการสร้าง 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
หรือคลาสย่อยใดคลาสหนึ่งของBlockly.Field
) เพื่อเริ่มต้นค่าอย่างถูกต้องและตั้งค่าโปรแกรมตรวจสอบในพื้นที่สำหรับช่อง - หากช่องเป็นรูปแบบที่นําเข้าได้ ให้ตั้งค่าพร็อพเพอร์ตี้ที่เกี่ยวข้องในคอนสตรคเตอร์ ช่องที่แก้ไขได้ต้องจัดเก็บเป็นอนุกรมได้ และช่องจะแก้ไขได้โดยค่าเริ่มต้น คุณจึงควรตั้งค่าพร็อพเพอร์ตี้นี้เป็น "จริง" เว้นแต่คุณจะทราบว่าไม่ควรจัดเก็บเป็นอนุกรม
- ไม่บังคับ: ใช้การปรับแต่งเพิ่มเติม (เช่น ช่องป้ายกำกับอนุญาตให้ส่งคลาส css ซึ่งจะใช้กับข้อความ)
JSON และการลงทะเบียน
ในคําจํากัดความของบล็อก JSON ช่องจะอธิบายด้วยสตริง (เช่น field_number
, field_textinput
) Blockly จะเก็บแผนที่จากสตริงเหล่านี้ไปยังออบเจ็กต์ฟิลด์ และเรียก 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
ของซุปเปอร์คลาสก่อนเพิ่มองค์ประกอบ DOM ที่เหลือ หากต้องการให้ช่องมีองค์ประกอบเหล่านี้เพียงอย่างเดียว (ไม่ใช่ทั้ง 2 อย่าง) ให้ใช้ฟังก์ชัน createBorderRect_
หรือ createTextElement_
การปรับแต่งการสร้าง DOM
หากช่องเป็นช่องข้อความทั่วไป (เช่น Text input) ระบบจะจัดการการสร้าง DOM ให้คุณ ไม่เช่นนั้น คุณจะต้องลบล้างฟังก์ชัน initView
เพื่อสร้างองค์ประกอบ DOM ที่จําเป็นในระหว่างการแสดงผลช่องในอนาคต
เช่น ช่องแบบเลื่อนลงอาจมีทั้งรูปภาพและข้อความ ใน initView
ระบบจะสร้างองค์ประกอบรูปภาพรายการเดียวและองค์ประกอบข้อความรายการเดียว จากนั้นในช่วง render_
ระบบจะแสดงองค์ประกอบที่ใช้งานอยู่และซ่อนองค์ประกอบอื่นๆ โดยอิงตามประเภทของตัวเลือกที่เลือก
การสร้างองค์ประกอบ DOM ทำได้โดยใช้เมธอด Blockly.utils.dom.createSvgElement
หรือใช้เมธอดการสร้าง DOM แบบดั้งเดิมก็ได้
ข้อกำหนดของการแสดงในบล็อกของฟิลด์มีดังนี้
- องค์ประกอบ DOM ทั้งหมดต้องเป็นองค์ประกอบย่อยของ
fieldGroup_
ของช่อง ระบบจะสร้างกลุ่มช่องโดยอัตโนมัติ - องค์ประกอบ DOM ทั้งหมดต้องอยู่ภายในมิติข้อมูลที่รายงานของช่อง
ดูรายละเอียดเพิ่มเติมเกี่ยวกับการปรับแต่งและการอัปเดตการแสดงผลในบล็อกได้ที่ส่วนการแสดงผล
การเพิ่มสัญลักษณ์ข้อความ
หากต้องการเพิ่มสัญลักษณ์ลงในข้อความของช่อง (เช่น สัญลักษณ์องศาของช่องมุม) คุณสามารถเพิ่มองค์ประกอบสัญลักษณ์ (ปกติจะอยู่ใน <tspan>
) ต่อท้าย textElement_
ของช่องได้โดยตรง
เหตุการณ์การป้อนข้อมูล
โดยค่าเริ่มต้น ช่องจะลงทะเบียนเหตุการณ์เคล็ดลับเครื่องมือและเหตุการณ์ mousedown (เพื่อใช้สำหรับการแสดงเครื่องมือแก้ไข)
หากต้องการฟังเหตุการณ์ประเภทอื่นๆ (เช่น หากต้องการจัดการการลากในช่อง) คุณควรลบล้างฟังก์ชัน 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
ถูกต้อง คุณจะได้รับ callback 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
แทนที่จะตรวจสอบพร็อพเพอร์ตี้แต่ละรายการอีกครั้งทีละรายการ
รูปแบบนี้สำหรับการตรวจสอบค่าแบบหลายส่วนยังใช้ในโปรแกรมตรวจสอบในเครื่องได้ด้วย แต่ปัจจุบันยังไม่มีวิธีบังคับใช้รูปแบบนี้
isDirty_
isDirty_
เป็น Flag ที่ใช้ในฟังก์ชัน 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
เรียกว่าในบริบทของ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
ด้วย ฟิลด์ที่ใช้โดยปกติจะอ้างอิงสถานะที่แปลงเป็นอนุกรมโดยSerializer อื่น (เช่น โมเดลข้อมูลสำรอง) พารามิเตอร์จะส่งสัญญาณว่าสถานะที่อ้างอิงจะไม่พร้อมใช้งานเมื่อมีการแปลงค่าบล็อกกลับ ดังนั้นช่องจึงควรทำการจัดรูปแบบทั้งหมดด้วยตนเอง ตัวอย่างเช่น กรณีนี้จะเกิดขึ้นเมื่อมีการอนุกรมบล็อกแต่ละบล็อก หรือเมื่อมีการคัดลอกและวางบล็อก
กรณีการใช้งานที่พบบ่อย 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 แบบเก่า ใช้ฮุกเหล่านี้เฉพาะในกรณีที่จำเป็นเท่านั้น (เช่น คุณกําลังทํางานในโค้ดเบสเก่าที่ยังไม่ได้ย้ายข้อมูล) มิเช่นนั้นให้ใช้ 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
ซึ่งเป็นเคอร์เซอร์สำหรับจับ