ตัวสร้างโค้ดบล็อกคือฟังก์ชันที่สร้างโค้ดสําหรับบล็อกและแสดงผลเป็นสตริง รหัสที่บล็อกสร้างขึ้นจะขึ้นอยู่กับประเภทของบล็อก ดังนี้
- บล็อกค่ามีการเชื่อมต่อเอาต์พุต บล็อกเหล่านี้ทํางานเหมือนนิพจน์ในภาษาแบบข้อความและสร้างสตริงที่มีนิพจน์
- บล็อกคำสั่งคือบล็อกที่ไม่มีการเชื่อมต่อเอาต์พุต บล็อกเหล่านี้ทํางานเหมือนคำสั่งในภาษาแบบข้อความและสร้างสตริงที่มีคำสั่ง
วิธีเขียนเครื่องมือสร้างโค้ดบล็อก
สําหรับบล็อกที่กําหนดเองแต่ละรายการที่คุณสร้าง คุณต้องเขียนเครื่องมือสร้างโค้ดบล็อกสําหรับแต่ละภาษาที่คุณต้องการรองรับ โปรดทราบว่าเครื่องมือสร้างโค้ดบล็อกทั้งหมดเขียนด้วย JavaScript แม้ว่าจะสร้างโค้ดในภาษาอื่นก็ตาม
เครื่องมือสร้างโค้ดบล็อกทั้งหมดจะทําตามขั้นตอนต่อไปนี้
- นําเข้าเครื่องมือสร้างรหัสภาษา
- รับค่าของช่องแต่ละช่องและเปลี่ยนรูปแบบเป็นสตริงโค้ด
- รับสตริงโค้ดที่บล็อกภายในสร้างขึ้น ซึ่งเป็นบล็อกที่แนบมากับค่าและอินพุตคำสั่ง
- สร้างและแสดงสตริงโค้ดของบล็อก
ตัวอย่างบล็อก
ตัวอย่างที่เราจะเขียนคือเครื่องมือสร้างโค้ด JavaScript สําหรับบล็อกต่อไปนี้
custom_compare
คือบล็อกค่าที่มีอินพุตค่าชื่อLEFT
, ช่องแบบเลื่อนลงชื่อOPERATOR
และช่องตัวเลขชื่อRIGHT
โดยจะสร้างสตริงนิพจน์ในรูปแบบ'0 = 0'
custom_if
คือบล็อกคำสั่งที่มีช่องช่องทําเครื่องหมายชื่อNOT
, อินพุตค่าชื่อCONDITION
และอินพุตคำสั่งชื่อTHEN
โดยจะสร้างสตริงคำสั่งของรูปแบบ'if (...) {\n...\n};\n'
เอกสารนี้จะอธิบายการสร้างเครื่องกำเนิดไฟฟ้าทีละขั้นตอน คุณดูเครื่องกำเนิดไฟฟ้าที่เสร็จสมบูรณ์ได้ที่ท้ายเอกสารนี้
โปรดทราบว่าบล็อกเหล่านี้มีไว้เพื่อแสดงการสร้างโค้ดเท่านั้น ในแอปพลิเคชันจริง ให้ใช้บล็อก 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;
}