ก่อนที่จะสร้างประเภทฟิลด์ใหม่ โปรดพิจารณาประเภท วิธีการ เพื่อปรับแต่งช่องให้ตรงตามความต้องการของคุณ หากแอปพลิเคชันของคุณต้องจัดเก็บ ประเภทค่าใหม่ หรือคุณต้องการสร้าง UI ใหม่สำหรับประเภทค่าที่มีอยู่ อาจต้องสร้างประเภทช่องใหม่
ในการสร้างช่องใหม่ ให้ทำดังนี้
- ใช้ตัวสร้าง
- ลงทะเบียนคีย์ JSON และใช้งาน
fromJson
- จัดการการเริ่มต้น UI และเหตุการณ์แบบออนบล็อก Listener
- จัดการการกำจัด Listener เหตุการณ์ (การกำจัด UI ได้รับการจัดการสำหรับ คุณ)
- ใช้การจัดการมูลค่า
- เพิ่มข้อความที่แสดงถึงค่าของช่องเพื่อการช่วยเหลือพิเศษ
- เพิ่มฟังก์ชันอื่นๆ เช่น
- กำหนดค่าด้านอื่นๆ ของช่อง เช่น
ส่วนนี้จะถือว่าคุณได้อ่านและคุ้นเคยกับเนื้อหาใน โครงสร้างของ ช่อง
สำหรับตัวอย่างของฟิลด์ที่กำหนดเอง ให้ดูที่ช่องที่กำหนดเอง เดโม ที่ใช้เวลาเพียง 2 นาที
การใช้ตัวสร้าง
เครื่องมือสร้างของช่องมีหน้าที่ในการตั้งค่าเริ่มต้นของฟิลด์ และเลือกตั้งค่า โปรแกรมตรวจสอบ บรรทัดที่กำหนดเอง มีการเรียกตัวสร้างของฟิลด์ในระหว่างการเริ่มต้นการบล็อกแหล่งที่มาโดยไม่คำนึงถึง มีการกำหนดการบล็อกแหล่งที่มาใน JSON หรือ JavaScript หรือไม่ ดังนั้น คอลัมน์ที่กำหนดเอง ไม่มีสิทธิ์เข้าถึงบล็อกแหล่งที่มาในระหว่างการสร้าง
ตัวอย่างโค้ดต่อไปนี้สร้างช่องที่กำหนดเองชื่อ GenericField
class GenericField extends Blockly.Field {
constructor(value, validator) {
super(value, validator);
this.SERIALIZABLE = true;
}
}
ลายเซ็นเมธอด
โดยปกติแล้วเครื่องมือสร้างช่องจะใช้ค่าและเครื่องมือตรวจสอบในเครื่อง ค่าจะเป็น
ไม่บังคับ และหากคุณไม่ส่งค่า (หรือคุณส่งค่าที่ไม่ผ่านคลาส
การตรวจสอบความถูกต้อง) ค่าเริ่มต้นของ Superclass จะถูกนำมาใช้ สำหรับ
คลาส Field
เริ่มต้น ค่าดังกล่าวคือ null
หากไม่ต้องการใช้ค่าเริ่มต้น
จากนั้นตรวจสอบว่าได้ส่งค่าที่เหมาะสม พารามิเตอร์โปรแกรมตรวจสอบ
แสดงสำหรับฟิลด์ที่แก้ไขได้ และมักจะทำเครื่องหมายว่าไม่บังคับ ดูข้อมูลเพิ่มเติม
เกี่ยวกับโปรแกรมตรวจสอบในโปรแกรมตรวจสอบ
เอกสาร
โครงสร้าง
ตรรกะภายในตัวสร้างของคุณควรเป็นไปตามขั้นตอนนี้
- เรียกใช้ตัวสร้างระดับสูงที่รับช่วงมา (ช่องที่กำหนดเองทั้งหมดควรรับค่าจาก
Blockly.Field
หรือคลาสย่อยใดคลาสหนึ่ง) เพื่อเริ่มต้นค่าอย่างถูกต้อง แล้วตั้งค่าโปรแกรมตรวจสอบในเครื่องสำหรับฟิลด์ของคุณ - หากฟิลด์ของคุณทำให้เป็นอนุกรม ให้ตั้งค่าคุณสมบัติที่เกี่ยวข้องใน เครื่องมือสร้างขึ้นมา ช่องที่แก้ไขได้ต้องทำให้ต่อเนื่องได้ และช่องที่แก้ไขได้ โดยค่าเริ่มต้น ดังนั้นคุณควรตั้งค่าคุณสมบัตินี้เป็น "จริง" เว้นแต่คุณจะทราบ ก็ไม่ควรทำให้ต่อเนื่องได้
- ไม่บังคับ: ใช้การปรับแต่งเพิ่มเติม (เช่น ช่องป้ายกำกับ อนุญาตให้ส่งผ่านคลาส 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
หากต้องการให้ช่องมีทั้ง 2 อย่างนี้พร้อมรายการเพิ่มเติม
ของดีๆ ให้เรียกฟังก์ชัน initView
ของ Superclass ก่อนเพิ่มส่วนที่เหลือ
องค์ประกอบ DOM หากคุณต้องการให้ฟิลด์มีอย่างใดอย่างหนึ่ง แต่ไม่ใช่ทั้ง 2 อย่าง
องค์ประกอบที่คุณสามารถใช้ฟังก์ชัน createBorderRect_
หรือ createTextElement_
การปรับแต่งการสร้าง DOM
หากฟิลด์ของคุณเป็นฟิลด์ข้อความทั่วไป (เช่น Text
อินพุต)
เราจะจัดการการสร้าง DOM ให้คุณ มิฉะนั้นคุณจะต้องลบล้าง
ฟังก์ชัน initView
เพื่อสร้างเอลิเมนต์ DOM ที่คุณจะต้องใช้
การแสดงภาพ
ครั้งต่อไปในอนาคต
เช่น ช่องแบบเลื่อนลงอาจมีทั้งรูปภาพและข้อความ ในinitView
จะสร้างองค์ประกอบรูปภาพ 1 รายการและองค์ประกอบข้อความ 1 รายการ จากนั้นระหว่าง 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_
Callback โดยค่าเริ่มต้น ฟังก์ชัน doValueUpdate_
จะมีลักษณะดังนี้
- ตั้งค่าพร็อพเพอร์ตี้
value_
เป็นnewValue
- ตั้งค่า
isDirty_
พร็อพเพอร์ตี้ไปยังtrue
หากคุณเพียงต้องการเก็บมูลค่า และไม่ต้องการจัดการด้วยตนเอง
คุณไม่จำเป็นต้องลบล้าง doValueUpdate_
หรือไม่เช่นนั้น หากคุณต้องการทำสิ่งต่างๆ ดังต่อไปนี้
- พื้นที่เก็บข้อมูลที่กำหนดเองของ
newValue
- เปลี่ยนพร็อพเพอร์ตี้อื่นๆ ตาม
newValue
- บันทึกว่าค่าปัจจุบันถูกต้องหรือไม่
คุณจะต้องลบล้าง doValueUpdate_
doValueUpdate_(newValue) {
super.doValueUpdate_(newValue);
this.displayValue_ = newValue;
this.isValueValid_ = true;
}
การจัดการค่าที่ไม่ถูกต้อง
หากค่าที่ส่งไปยังช่อง setValue
ไม่ถูกต้อง คุณจะได้รับ
doValueInvalid_
Callback โดยค่าเริ่มต้น ฟังก์ชัน 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
ข้อความ
→ สำหรับข้อมูลเกี่ยวกับตำแหน่งที่ใช้ข้อความในช่องและความแตกต่าง จากค่าของช่อง โปรดดูการวิเคราะห์
หากข้อความในช่องแตกต่างจากค่าของช่อง คุณควร
ลบล้าง
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
ไม่ว่าจะเป็นกรณีใด
เราขอแนะนำให้ใช้
เชื่อมโยง
เมื่อส่งฟังก์ชันกำจัด ดังที่แสดงใน DropDownDiv
ด้านบน
และตัวอย่าง WidgetDiv
รายการ
→ สำหรับข้อมูลเกี่ยวกับการกำจัดที่ไม่ได้เจาะจงเฉพาะการกำจัดเอดิเตอร์ โปรดดู การกำจัด
กำลังอัปเดตจอแสดงผลที่แสดงบนบล็อก
ใช้ฟังก์ชัน render_
เพื่ออัปเดตการแสดงผลแบบออนบล็อกของช่องให้ตรงกัน
มูลค่าภายใน
ตัวอย่างที่พบบ่อยมีดังนี้
- เปลี่ยนข้อความ (รายการแบบเลื่อนลง)
- เปลี่ยนสี (สี)
ค่าเริ่มต้น
ฟังก์ชัน render_
เริ่มต้นจะตั้งค่าข้อความที่แสดงเป็นผลลัพธ์ของ
getDisplayText_
ฟังก์ชัน getDisplayText_
จะแสดงผลพร็อพเพอร์ตี้ value_
ของช่อง
แคสต์ไปยังสตริง หลังจากถูกตัดให้สั้นลงตามจํานวนข้อความสูงสุด
หากคุณใช้การแสดงผลบนบล็อกซึ่งเป็นค่าเริ่มต้นและลักษณะการทำงานสำหรับข้อความเริ่มต้น
ใช้ได้กับฟิลด์ของคุณ คุณไม่จำเป็นต้องแทนที่ render_
หากการทำงานของข้อความตามค่าเริ่มต้นใช้ได้กับช่องของคุณ แต่ช่องอยู่ในบล็อก
display มีองค์ประกอบแบบคงที่เพิ่มเติม คุณสามารถเรียกใช้ 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 ชุดสำหรับช่อง ตะขอ 1 คู่ จะทำงานร่วมกับระบบการเรียงอันดับ 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 หรือไม่เพื่อระบุว่าช่องใดควรมี UI
ที่โต้ตอบกับแท็กได้ โดยมีค่าเริ่มต้นเป็น true
พร็อพเพอร์ตี้ SERIALIZABLE
จะระบุว่าควรเรียงลำดับช่องนี้หรือไม่ ทั้งนี้
ค่าเริ่มต้นคือ false
หากพร็อพเพอร์ตี้นี้คือ true
คุณอาจต้องระบุ
ฟังก์ชันการทำให้เป็นอนุกรมและดีซีเรียลไลซ์ (โปรดดู
การทำให้เป็นอนุกรม)
การกำหนดค่าเคอร์เซอร์
พร็อพเพอร์ตี้ CURSOR
กําหนดเคอร์เซอร์ที่ผู้ใช้จะเห็นเมื่อวางเมาส์เหนือ
ฟิลด์ของคุณ สตริงนี้ควรเป็นสตริงเคอร์เซอร์ CSS ที่ถูกต้อง ค่าเริ่มต้นของเคอร์เซอร์จะเป็น
กำหนดโดย .blocklyDraggable
ซึ่งเป็นเคอร์เซอร์แบบจับ