การสร้างประเภทช่องใหม่

ก่อนที่จะสร้างประเภทฟิลด์ใหม่ โปรดพิจารณาประเภท วิธีการ เพื่อปรับแต่งช่องให้ตรงตามความต้องการของคุณ หากแอปพลิเคชันของคุณต้องจัดเก็บ ประเภทค่าใหม่ หรือคุณต้องการสร้าง UI ใหม่สำหรับประเภทค่าที่มีอยู่ อาจต้องสร้างประเภทช่องใหม่

ในการสร้างช่องใหม่ ให้ทำดังนี้

  1. ใช้ตัวสร้าง
  2. ลงทะเบียนคีย์ JSON และใช้งาน fromJson
  3. จัดการการเริ่มต้น UI และเหตุการณ์แบบออนบล็อก Listener
  4. จัดการการกำจัด Listener เหตุการณ์ (การกำจัด UI ได้รับการจัดการสำหรับ คุณ)
  5. ใช้การจัดการมูลค่า
  6. เพิ่มข้อความที่แสดงถึงค่าของช่องเพื่อการช่วยเหลือพิเศษ
  7. เพิ่มฟังก์ชันอื่นๆ เช่น
  8. กำหนดค่าด้านอื่นๆ ของช่อง เช่น

ส่วนนี้จะถือว่าคุณได้อ่านและคุ้นเคยกับเนื้อหาใน โครงสร้างของ ช่อง

สำหรับตัวอย่างของฟิลด์ที่กำหนดเอง ให้ดูที่ช่องที่กำหนดเอง เดโม ที่ใช้เวลาเพียง 2 นาที

การใช้ตัวสร้าง

เครื่องมือสร้างของช่องมีหน้าที่ในการตั้งค่าเริ่มต้นของฟิลด์ และเลือกตั้งค่า โปรแกรมตรวจสอบ บรรทัดที่กำหนดเอง มีการเรียกตัวสร้างของฟิลด์ในระหว่างการเริ่มต้นการบล็อกแหล่งที่มาโดยไม่คำนึงถึง มีการกำหนดการบล็อกแหล่งที่มาใน JSON หรือ JavaScript หรือไม่ ดังนั้น คอลัมน์ที่กำหนดเอง ไม่มีสิทธิ์เข้าถึงบล็อกแหล่งที่มาในระหว่างการสร้าง

ตัวอย่างโค้ดต่อไปนี้สร้างช่องที่กำหนดเองชื่อ GenericField

class GenericField extends Blockly.Field {
  constructor(value, validator) {
    super(value, validator);

    this.SERIALIZABLE = true;
  }
}

ลายเซ็นเมธอด

โดยปกติแล้วเครื่องมือสร้างช่องจะใช้ค่าและเครื่องมือตรวจสอบในเครื่อง ค่าจะเป็น ไม่บังคับ และหากคุณไม่ส่งค่า (หรือคุณส่งค่าที่ไม่ผ่านคลาส การตรวจสอบความถูกต้อง) ค่าเริ่มต้นของ Superclass จะถูกนำมาใช้ สำหรับ คลาส Field เริ่มต้น ค่าดังกล่าวคือ null หากไม่ต้องการใช้ค่าเริ่มต้น จากนั้นตรวจสอบว่าได้ส่งค่าที่เหมาะสม พารามิเตอร์โปรแกรมตรวจสอบ แสดงสำหรับฟิลด์ที่แก้ไขได้ และมักจะทำเครื่องหมายว่าไม่บังคับ ดูข้อมูลเพิ่มเติม เกี่ยวกับโปรแกรมตรวจสอบในโปรแกรมตรวจสอบ เอกสาร

โครงสร้าง

ตรรกะภายในตัวสร้างของคุณควรเป็นไปตามขั้นตอนนี้

  1. เรียกใช้ตัวสร้างระดับสูงที่รับช่วงมา (ช่องที่กำหนดเองทั้งหมดควรรับค่าจาก Blockly.Field หรือคลาสย่อยใดคลาสหนึ่ง) เพื่อเริ่มต้นค่าอย่างถูกต้อง แล้วตั้งค่าโปรแกรมตรวจสอบในเครื่องสำหรับฟิลด์ของคุณ
  2. หากฟิลด์ของคุณทำให้เป็นอนุกรม ให้ตั้งค่าคุณสมบัติที่เกี่ยวข้องใน เครื่องมือสร้างขึ้นมา ช่องที่แก้ไขได้ต้องทำให้ต่อเนื่องได้ และช่องที่แก้ไขได้ โดยค่าเริ่มต้น ดังนั้นคุณควรตั้งค่าคุณสมบัตินี้เป็น "จริง" เว้นแต่คุณจะทราบ ก็ไม่ควรทำให้ต่อเนื่องได้
  3. ไม่บังคับ: ใช้การปรับแต่งเพิ่มเติม (เช่น ช่องป้ายกำกับ อนุญาตให้ส่งผ่านคลาส 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 ใช้เพื่อจัดเตรียมเอดิเตอร์ที่อยู่ภายในกล่องที่เชื่อมต่อ ลงในช่อง โดยจะวางตำแหน่งตัวเองให้อยู่ใกล้สนามโดยอัตโนมัติในขณะที่อยู่ตรงนั้น ภายในขอบเขตที่มองเห็นได้ ตัวเลือกมุมและตัวเลือกสีเป็นตัวอย่างที่ดีของ DropDownDiv

รูปภาพของเครื่องมือเลือกมุม

WidgetDiv ใช้เพื่อ จัดเตรียมเครื่องมือแก้ไขที่ไม่ได้อยู่ภายในกล่อง ฟิลด์ตัวเลขใช้ฟิลด์ WidgetDiv นี้ครอบคลุมช่องด้วยกล่องป้อนข้อความ HTML ขณะที่ DropDownDiv จัดการเรื่องตำแหน่งให้คุณ แต่ WidgetDiv ไม่ได้ดูแล องค์ประกอบจะต้อง ด้วยตนเอง ระบบพิกัดอยู่ในพิกัดพิกเซลที่สัมพันธ์กับ ด้านซ้ายบนของหน้าต่าง เครื่องมือแก้ไขการป้อนข้อความเป็นตัวอย่างที่ดีของ WidgetDiv

รูปภาพของตัวแก้ไขการป้อนข้อความ

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_ ฟังก์ชัน

โฟลว์ชาร์ตที่อธิบายวิธีตัดสินใจว่าจะลบล้าง Display_ หรือไม่

การปรับแต่งการแสดงผล

หากลักษณะการแสดงผลเริ่มต้นใช้ไม่ได้กับฟิลด์ของคุณ คุณจะต้อง กำหนดลักษณะการแสดงผลที่กำหนดเอง ซึ่งอาจเกี่ยวข้องกับอะไรก็ได้ ตั้งแต่การตั้งค่าแบบกำหนดเอง แสดงข้อความ การเปลี่ยนองค์ประกอบของภาพ การอัปเดตสีพื้นหลัง

การเปลี่ยนแปลงแอตทริบิวต์ DOM ทั้งหมดนั้นถูกกฎหมาย แต่ข้อควรจำ 2 อย่างคือ

  1. ควรจัดการการสร้าง DOM ระหว่าง การเริ่มต้น เนื่องจากมีประสิทธิภาพมากกว่า
  2. คุณควรอัปเดต 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 ซึ่งเป็นเคอร์เซอร์แบบจับ