ก่อนสร้างประเภทฟิลด์ใหม่ ให้พิจารณาว่าวิธีอื่นๆ ในการปรับแต่งฟิลด์เหมาะกับความต้องการของคุณหรือไม่ หากแอปพลิเคชันของคุณต้องจัดเก็บค่าประเภทใหม่ หรือคุณต้องการสร้าง UI ใหม่สำหรับค่าประเภทที่มีอยู่ คุณอาจต้องสร้างประเภทฟิลด์ใหม่
หากต้องการสร้างฟิลด์ใหม่ ให้ทำดังนี้
- ใช้ตัวสร้าง
- ลงทะเบียนคีย์ JSON และใช้
fromJson
- จัดการการเริ่มต้น UI และเครื่องมือฟังเหตุการณ์ on-block
- จัดการการทิ้ง 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
) 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
จะสร้างองค์ประกอบรูปภาพ 1 รายการและองค์ประกอบข้อความ 1 รายการ จากนั้นในระหว่าง 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 ของฟิลด์โดยอัตโนมัติ
การจัดการมูลค่า
→ ดูข้อมูลเกี่ยวกับค่าของฟิลด์เทียบกับข้อความได้ที่โครงสร้างของฟิลด์
ลำดับการตรวจสอบ
การใช้เครื่องมือตรวจสอบคลาส
ฟิลด์ควรยอมรับเฉพาะค่าบางค่า เช่น ช่องตัวเลขควรรับเฉพาะตัวเลข ช่องสีควรรับเฉพาะสี ฯลฯ ซึ่งจะได้รับการตรวจสอบผ่านคลาสและเครื่องมือตรวจสอบในเครื่อง คลาส Validator จะใช้กฎเดียวกันกับ Validator ในเครื่อง ยกเว้นว่าจะเรียกใช้ใน Constructor ด้วย และด้วยเหตุนี้ จึงไม่ควรอ้างอิงบล็อกต้นทาง
หากต้องการใช้เครื่องมือตรวจสอบคลาสของฟิลด์ ให้ลบล้าง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
แทนที่จะต้องตรวจสอบพร็อพเพอร์ตี้แต่ละรายการอีกครั้ง
รูปแบบนี้สำหรับการตรวจสอบค่าแบบหลายส่วนยังใช้ในเครื่องมือตรวจสอบ ในเครื่องได้ด้วย แต่ปัจจุบันยังไม่มีวิธีบังคับใช้รูปแบบนี้
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
พิเศษ 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
เมื่อส่งฟังก์ชัน dispose ดังที่แสดงในตัวอย่าง 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 แบบเก่า
ใช้ฮุกเหล่านี้เฉพาะในกรณีที่จำเป็น (เช่น คุณกำลังทำงานในโค้ดเบสเก่าที่ยังไม่ได้ย้ายข้อมูล) ไม่เช่นนั้นให้ใช้ 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
คุณอาจต้องระบุฟังก์ชันการซีเรียลไลซ์และการดีซีเรียลไลซ์ (ดูการซีเรียลไลซ์)
การปรับแต่งด้วย CSS
คุณปรับแต่งฟิลด์ได้ด้วย CSS ในinitView
เมธอด ให้เพิ่มคลาสที่กำหนดเองลงใน fieldGroup_
ของฟิลด์
จากนั้นอ้างอิงคลาสนี้ใน CSS
เช่น หากต้องการใช้เคอร์เซอร์อื่น ให้ทำดังนี้
initView() {
...
// Add a custom CSS class.
if (this.fieldGroup_) {
Blockly.utils.dom.addClass(this.fieldGroup_, 'myCustomField');
}
}
.myCustomField {
cursor: cell;
}
การปรับแต่งเคอร์เซอร์
โดยค่าเริ่มต้น คลาสที่ขยาย FieldInput
จะใช้เคอร์เซอร์ text
เมื่อผู้ใช้
วางเมาส์เหนือช่อง ฟิลด์ที่ลากจะใช้เคอร์เซอร์ grabbing
และฟิลด์อื่นๆ ทั้งหมด
จะใช้เคอร์เซอร์ default
หากต้องการใช้เคอร์เซอร์อื่น ให้ตั้งค่าโดยใช้ CSS