เครื่องมือสร้างโค้ดบล็อก

ตัวสร้างโค้ดบล็อกคือฟังก์ชันที่สร้างโค้ดสําหรับบล็อกและแสดงผลเป็นสตริง รหัสที่บล็อกสร้างขึ้นจะขึ้นอยู่กับประเภทของบล็อก ดังนี้

  • บล็อกค่ามีการเชื่อมต่อเอาต์พุต บล็อกเหล่านี้ทํางานเหมือนนิพจน์ในภาษาแบบข้อความและสร้างสตริงที่มีนิพจน์
  • บล็อกคำสั่งคือบล็อกที่ไม่มีการเชื่อมต่อเอาต์พุต บล็อกเหล่านี้ทํางานเหมือนคำสั่งในภาษาแบบข้อความและสร้างสตริงที่มีคำสั่ง

วิธีเขียนเครื่องมือสร้างโค้ดบล็อก

สําหรับบล็อกที่กําหนดเองแต่ละรายการที่คุณสร้าง คุณต้องเขียนเครื่องมือสร้างโค้ดบล็อกสําหรับแต่ละภาษาที่คุณต้องการรองรับ โปรดทราบว่าเครื่องมือสร้างโค้ดบล็อกทั้งหมดเขียนด้วย JavaScript แม้ว่าจะสร้างโค้ดในภาษาอื่นก็ตาม

เครื่องมือสร้างโค้ดบล็อกทั้งหมดจะทําตามขั้นตอนต่อไปนี้

  1. นําเข้าเครื่องมือสร้างรหัสภาษา
  2. รับค่าของช่องแต่ละช่องและเปลี่ยนรูปแบบเป็นสตริงโค้ด
  3. รับสตริงโค้ดที่บล็อกภายในสร้างขึ้น ซึ่งเป็นบล็อกที่แนบมากับค่าและอินพุตคำสั่ง
  4. สร้างและแสดงสตริงโค้ดของบล็อก

ตัวอย่างบล็อก

ตัวอย่างที่เราจะเขียนคือเครื่องมือสร้างโค้ด JavaScript สําหรับบล็อกต่อไปนี้

  • custom_compare คือบล็อกค่าที่มีอินพุตค่าชื่อ LEFT, ช่องแบบเลื่อนลงชื่อ OPERATOR และช่องตัวเลขชื่อ RIGHT โดยจะสร้างสตริงนิพจน์ในรูปแบบ '0 = 0'

    บล็อกค่าที่กำหนดเองสำหรับการเปรียบเทียบ

  • custom_if คือบล็อกคำสั่งที่มีช่องช่องทําเครื่องหมายชื่อ NOT, อินพุตค่าชื่อ CONDITION และอินพุตคำสั่งชื่อ THEN โดยจะสร้างสตริงคำสั่งของรูปแบบ 'if (...) {\n...\n};\n'

    บล็อกคำสั่งที่กำหนดเองสำหรับคำสั่ง if ผู้ใช้สามารถใช้ช่องทําเครื่องหมายเพื่อปฏิเสธเงื่อนไข if

เอกสารนี้จะอธิบายการสร้างเครื่องกำเนิดไฟฟ้าทีละขั้นตอน คุณดูเครื่องกำเนิดไฟฟ้าที่เสร็จสมบูรณ์ได้ที่ท้ายเอกสารนี้

โปรดทราบว่าบล็อกเหล่านี้มีไว้เพื่อแสดงการสร้างโค้ดเท่านั้น ในแอปพลิเคชันจริง ให้ใช้บล็อก logic_compare และ controls_if ในตัว

นําเข้าเครื่องมือสร้างรหัสภาษา

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

โมดูล

import {javascriptGenerator} from 'blockly/javascript';
import {pythonGenerator} from 'blockly/python';
import {phpGenerator} from 'blockly/php';
import {luaGenerator} from 'blockly/lua';
import {dartGenerator} from 'blockly/dart';

// Add block-code generators for the custom_if block.
javascriptGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
pythonGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
phpGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
luaGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
dartGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };

Unpkg

คุณต้องใส่เครื่องมือสร้างหลังจากใส่ Blockly

<script src="https://unpkg.com/blockly"></script>
<script src="https://unpkg.com/blockly/javascript_compressed"></script>
<script src="https://unpkg.com/blockly/python_compressed"></script>
<script src="https://unpkg.com/blockly/php_compressed"></script>
<script src="https://unpkg.com/blockly/lua_compressed"></script>
<script src="https://unpkg.com/blockly/dart_compressed"></script>
// Add block-code generators for the custom_if block.
javascript.javascriptGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
python.pythonGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
php.phpGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
lua.luaGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
dart.dartGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };

สคริปต์ในเครื่อง

คุณต้องใส่เครื่องมือสร้างหลังจากใส่ Blockly

<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>
<script src="python_compressed.js"></script>
<script src="php_compressed.js"></script>
<script src="lua_compressed.js"></script>
<script src="dart_compressed.js"></script>
// Add block-code generators for the custom_if block.
javascript.javascriptGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
python.pythonGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
php.phpGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
lua.luaGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
dart.dartGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };

รับค่าในช่อง

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

คุณอาจต้องเปลี่ยนรูปแบบค่าที่แสดงผลก่อนนำไปใช้กับโค้ด ทั้งนี้ขึ้นอยู่กับฟิลด์

custom_compare

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  // Use the value of the OPERATOR dropdown to look up the actual operator.
  const OPERATORS = {
    EQUALS: '==',
    LESS: '<',
    GREATER: '>',
  };
  const operator = OPERATORS[block.getFieldValue('OPERATOR')];
  // The value of the RIGHT field is a number and can be used directly when
  // building the block's code string.
  const right = block.getFieldValue('RIGHT');
  ...
}

custom_if

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  // Use the value of the NOT field to get the negation operator (if any).
  const checkbox = block.getFieldValue('NOT');
  const negate = checkbox === 'TRUE' ? '!' : '';
  ...
}

ดูข้อมูลเพิ่มเติมได้ที่เปลี่ยนรูปแบบค่า

รับโค้ดจากบล็อกภายใน

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

โค้ดที่คุณได้รับจากบล็อกภายในจะพร้อมใช้งานและไม่ต้องเปลี่ยนรูปแบบ ต่างจากค่าในช่อง

บล็อกค่าภายใน

หากต้องการรับโค้ดจากบล็อกภายในที่แนบมากับอินพุตค่า ให้เรียกใช้ valueToCode เมธอดนี้จะเรียกเครื่องมือสร้างโค้ดของบล็อกด้านใน

custom_compare

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  ...
  const order = operator === '==' ? Order.EQUALITY : Order.RELATIONAL;
  const left = generator.valueToCode(block, 'LEFT', order);
  ...
}

custom_if

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  ...
  const order = checkbox === 'TRUE' ? Order.LOGICAL_NOT : Order.NONE;
  const condition = generator.valueToCode(block, 'CONDITION', order) || 'false';
  ...
}

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

เช่น การเลือกช่อง NOT ใน custom_if จะใช้โอเปอเรเตอร์เชิงตรรกะ "ไม่ใช่" (!) กับเงื่อนไข ในกรณีนี้ คุณจะส่งลําดับชั้นของโอเปอเรเตอร์ "not" (Order.LOGICAL_NOT) ไปยัง valueToCode และ valueToCode จะเปรียบเทียบลําดับชั้นนี้กับลําดับชั้นของโอเปอเรเตอร์ที่มีลําดับชั้นน้อยที่สุดในบล็อกด้านใน จากนั้นจะตัดโค้ดของบล็อกด้านในตามต้องการ

  • หาก CONDITION เป็นบล็อกตัวแปร valueToCode จะไม่ใส่วงเล็บเนื่องจากโอเปอเรเตอร์ not ใช้กับตัวแปรได้โดยตรง (!myBoolean)
  • หาก CONDITION เป็นบล็อกการเปรียบเทียบ valueToCode จะเพิ่มวงเล็บเพื่อให้โอเปอเรเตอร์ "not" ใช้กับการเปรียบเทียบทั้งหมด (!(a < b)) แทนค่าด้านซ้าย (!a < b)

คุณไม่จำเป็นต้องทราบว่า valueToCode เพิ่มวงเล็บหรือไม่ คุณเพียงแค่ต้องส่งลําดับความสําคัญไปยัง valueToCode และเพิ่มโค้ดที่แสดงผลไปยังสตริงโค้ด ดูข้อมูลเพิ่มเติมได้ที่ valueToCode precedence

บล็อกคำสั่งภายใน

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

custom_compare

บล็อก custom_compare ไม่มีอินพุตคำสั่ง

custom_if

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  ...
  const statements = generator.statementToCode(block, 'THEN');
  ...
}

คุณเพียงต้องเรียกใช้ statementToCode สำหรับบล็อกด้านในที่เชื่อมต่อกับอินพุตคำสั่งโดยตรง statementToCode จะจัดการบล็อกเพิ่มเติมที่แนบมากับบล็อกแรก

สร้างและแสดงสตริงโค้ด

หลังจากได้รับโค้ดสําหรับช่องและบล็อกภายในแล้ว ให้สร้างและแสดงสตริงโค้ดสําหรับบล็อก สิ่งที่คุณส่งคืนจะขึ้นอยู่กับประเภทบล็อก ดังนี้

  • บล็อกค่า: แสดงผลอาร์เรย์ที่มีสตริงโค้ดและลําดับความสําคัญของโอเปอเรเตอร์ที่มีลําดับความสําคัญน้อยที่สุดในโค้ด valueToCode ใช้ค่านี้เพื่อตัดสินว่าต้องใส่โค้ดไว้ในวงเล็บหรือไม่เมื่อใช้บล็อกเป็นบล็อกภายใน ดูข้อมูลเพิ่มเติมได้ที่ลําดับความสําคัญของผลลัพธ์

  • บล็อกคำสั่ง: แสดงสตริงโค้ด

custom_compare

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  ...
  const order = operator === '==' ? Order.EQUALITY : Order.RELATIONAL;
  ...
  const code = left + ' ' + operator + ' ' + right;
  return [code, order];
}

custom_if

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  ...
  const code = 'if (' + negate + condition + ') {\n' + statements + '}\n';
  return code;
}

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

เครื่องมือสร้างโค้ดที่สมบูรณ์

ต่อไปนี้คือเครื่องมือสร้างโค้ดที่สมบูรณ์สำหรับแต่ละบล็อกเพื่อเป็นข้อมูลอ้างอิง

custom_compare

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  const OPERATORS = {
    EQUALS: '==',
    LESS: '<',
    GREATER: '>',
  };
  const operator = OPERATORS[block.getFieldValue('OPERATOR')];
  const order = operator === '==' ? Order.EQUALITY : Order.RELATIONAL;
  const left = generator.valueToCode(block, 'LEFT', order);
  const right = block.getFieldValue('RIGHT');
  const code = left + ' ' + operator + ' ' + right;
  return [code, order];
}

custom_if

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  const checkbox = block.getFieldValue('NOT');
  const negate = checkbox === 'TRUE' ? '!' : '';
  const order = checkbox === 'TRUE' ? Order.LOGICAL_NOT : Order.NONE;
  const condition = generator.valueToCode(block, 'CONDITION', order) || 'false';
  const statements = generator.statementToCode(block, 'THEN');
  const code = 'if (' + negate + condition + ') {\n' + statements + '}\n';
  return code;
}