เมนูบริบทมีรายการการดำเนินการที่ผู้ใช้สามารถทำกับคอมโพเนนต์ได้
เช่น พื้นที่ทำงาน บล็อก หรือความคิดเห็นในพื้นที่ทำงาน เมนูตามบริบทจะแสดงขึ้น
เมื่อคลิกขวาหรือกดค้างบนอุปกรณ์ระบบสัมผัส หากคุณใช้ปลั๊กอิน
@blockly/keyboard-navigation
ระบบจะแสดงปลั๊กอินพร้อมแป้นพิมพ์ลัด ซึ่งค่าเริ่มต้นคือ Ctrl+Enter
ใน Windows หรือ
Command+Enter
ใน Mac
เมนูบริบทเป็นที่ที่เหมาะสําหรับการเพิ่มการกระทําที่ผู้ใช้ทําไม่บ่อยนัก เช่น การดาวน์โหลดภาพหน้าจอ หากคิดว่าการดำเนินการจะ ใช้กันโดยทั่วไป คุณอาจต้องการสร้างวิธีเรียกใช้ที่ค้นพบได้ง่ายขึ้น
พื้นที่ทำงาน บล็อก ความคิดเห็นในพื้นที่ทำงาน บับเบิล และการเชื่อมต่อรองรับเมนูตามบริบท คุณยังใช้กับคอมโพเนนต์ที่กำหนดเองได้ด้วย Blockly มีเมนูบริบทมาตรฐาน ที่คุณปรับแต่งได้ นอกจากนี้ คุณยังปรับแต่งเมนูตามบริบทใน พื้นที่ทำงานและบล็อกได้ตามพื้นที่ทำงานหรือบล็อก
วิธีการทำงานของเมนูตามบริบท
Blockly มีรีจิสทรีที่มีเทมเพลตสำหรับรายการเมนูที่เป็นไปได้ทั้งหมด เทมเพลตแต่ละรายการจะอธิบายวิธีสร้างรายการเดียวในเมนูตามบริบท เมื่อ ผู้ใช้เรียกใช้เมนูตามบริบทในคอมโพเนนต์ คอมโพเนนต์จะทำดังนี้
ขอให้รีจิสทรีสร้างอาร์เรย์ของรายการเมนูที่ใช้กับคอมโพเนนต์ รีจิสทรีจะถามแต่ละเทมเพลตว่าเทมเพลตนั้นใช้กับคอมโพเนนต์ได้หรือไม่ และหากใช้ได้ ก็จะเพิ่มรายการเมนูที่เกี่ยวข้องลงในอาร์เรย์
หากคอมโพเนนต์เป็นพื้นที่ทำงานหรือบล็อก ระบบจะตรวจสอบว่าพื้นที่ทำงานหรือบล็อกที่เรียกใช้เมนูมีฟังก์ชันสำหรับ ปรับแต่งเมนูตามบริบทหรือไม่ หากเป็นเช่นนั้น ฟังก์ชันจะส่งอาร์เรย์ไปยังฟังก์ชัน ซึ่งสามารถเพิ่ม ลบ หรือแก้ไของค์ประกอบของอาร์เรย์ได้
แสดงเมนูตามบริบทโดยใช้อาร์เรย์ของรายการเมนูตามบริบท (อาจมีการแก้ไข)
Blockly กำหนดชุดเทมเพลตมาตรฐานสำหรับเมนูบริบทของ พื้นที่ทำงาน บล็อก และความคิดเห็นในพื้นที่ทำงาน โดยจะโหลดเทมเพลตสำหรับ พื้นที่ทำงานและบล็อกไว้ล่วงหน้าในรีจิสทรี หากต้องการใช้เทมเพลตสำหรับ ความคิดเห็นในพื้นที่ทำงาน คุณต้องโหลดลงในรีจิสทรีด้วยตนเอง
ดูข้อมูลเกี่ยวกับวิธีเพิ่ม ลบ และแก้ไขเทมเพลตในรีจิสทรีได้ที่ ปรับแต่งรีจิสทรี
ขอบเขต
เมนูตามบริบทจะได้รับการติดตั้งใช้งานโดยคอมโพเนนต์ประเภทต่างๆ ซึ่งรวมถึง พื้นที่ทำงาน ความคิดเห็นในพื้นที่ทำงาน การเชื่อมต่อ บล็อก บับเบิล และ คอมโพเนนต์ที่กำหนดเองของคุณเอง เมนูตามบริบทสำหรับคอมโพเนนต์แต่ละประเภทอาจมีรายการต่างๆ และรายการอาจทำงานแตกต่างกันไปตามประเภทคอมโพเนนต์ ดังนั้น ระบบเมนูตามบริบทจึงต้องทราบว่ามีการเรียกใช้คอมโพเนนต์ใด
เพื่อแก้ไขปัญหานี้ รีจิสทรีจึงใช้ออบเจ็กต์ Scope
คอมโพเนนต์ที่เรียกใช้เมนูบริบทจะจัดเก็บไว้ในพร็อพเพอร์ตี้ focusedNode
เป็นออบเจ็กต์
ที่ใช้ IFocusableNode
(IFocusableNode
ดำเนินการโดยคอมโพเนนต์ทั้งหมดที่ผู้ใช้สามารถโฟกัสได้ รวมถึงคอมโพเนนต์ที่ใช้เมนูบริบท ดูข้อมูลเพิ่มเติมได้ที่ระบบ
โฟกัส)
ระบบจะส่งออบเจ็กต์ Scope
ไปยังฟังก์ชันหลายรายการในเทมเพลต ในฟังก์ชันใดก็ตามที่รับออบเจ็กต์ Scope
คุณสามารถตัดสินใจว่าจะทำอะไรโดยอิงตามประเภท
ของออบเจ็กต์ในพร็อพเพอร์ตี้ focusedNode
เช่น คุณสามารถตรวจสอบได้ว่าคอมโพเนนต์เป็นบล็อกที่มีลักษณะดังนี้หรือไม่
if (scope.focusedNode instanceof Blockly.BlockSvg) {
// do something with the block
}
ออบเจ็กต์ Scope
มีพร็อพเพอร์ตี้อื่นๆ ที่ไม่บังคับซึ่งเราไม่แนะนำให้ใช้แล้ว แต่ยังคงตั้งค่าได้
block
จะตั้งค่าก็ต่อเมื่อคอมโพเนนต์ที่มีเมนูแสดงเป็นBlockSvg
- ระบบจะตั้งค่า
workspace
ก็ต่อเมื่อคอมโพเนนต์เป็นWorkspaceSvg
- ระบบจะตั้งค่า
comment
ก็ต่อเมื่อคอมโพเนนต์เป็นRenderedWorkspaceComment
พร็อพเพอร์ตี้เหล่านี้ไม่ได้ครอบคลุมคอมโพเนนต์ทุกประเภทที่อาจมีเมนูบริบท ดังนั้นคุณควรใช้พร็อพเพอร์ตี้ focusedNode
ประเภท RegistryItem
เทมเพลตมีประเภท ContextMenuRegistry.RegistryItem
ซึ่งมีพร็อพเพอร์ตี้ต่อไปนี้ โปรดทราบว่าพร็อพเพอร์ตี้ preconditionFn
,
displayText
และ callback
จะเป็นข้อมูลแยกกันกับพร็อพเพอร์ตี้ separator
รหัส
พร็อพเพอร์ตี้ id
ควรเป็นสตริงที่ไม่ซ้ำซึ่งระบุว่ารายการในเมนูบริบททำอะไร
const collapseTemplate = {
id: 'collapseBlock',
// ...
};
ฟังก์ชันเงื่อนไขเบื้องต้น
คุณใช้ preconditionFn
เพื่อจำกัดเวลาและวิธีแสดงรายการในเมนูตามบริบท
ได้
โดยควรแสดงผลสตริงชุดใดชุดหนึ่งต่อไปนี้ 'enabled'
, 'disabled'
หรือ 'hidden'
ค่า | คำอธิบาย | รูปภาพ |
---|---|---|
เปิดใช้อยู่ | แสดงว่า รายการใช้งานอยู่ | ![]() |
ปิดอยู่ | แสดงว่า รายการไม่ได้ ใช้งานอยู่ | ![]() |
ซ่อน | ซ่อนรายการ |
นอกจากนี้ preconditionFn
ยังส่ง Scope
ให้ด้วย ซึ่งคุณสามารถใช้เพื่อ
ระบุประเภทของคอมโพเนนต์ที่เปิดเมนู และสถานะของคอมโพเนนต์นั้น
ได้
ตัวอย่างเช่น คุณอาจต้องการให้รายการปรากฏเฉพาะในบล็อก และเฉพาะเมื่อบล็อกเหล่านั้นอยู่ในสถานะที่เฉพาะเจาะจงเท่านั้น
const collapseTemplate = {
// ...
preconditionFn: (scope) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
if (!scope.focusedNode.isCollapsed()) {
// The component is a block and it is not already collapsed
return 'enabled';
} else {
// The block is already collapsed
return 'disabled';
}
}
// The component is not a block
return 'hidden';
},
// ...
}
ข้อความที่แสดง
displayText
คือสิ่งที่ควรแสดงต่อผู้ใช้เป็นส่วนหนึ่งของรายการเมนู
ข้อความที่แสดงอาจเป็นสตริง, HTML หรือฟังก์ชันที่แสดงผลเป็นสตริงหรือ HTML
const collapseTemplate = {
// ...
displayText: 'Collapse block',
// ...
};
หากต้องการแสดงคำแปลจาก Blockly.Msg
คุณต้องใช้ฟังก์ชัน
หากพยายามกำหนดค่าโดยตรง ระบบอาจโหลดข้อความไม่ได้และคุณจะได้รับค่าเป็น undefined
แทน
const collapseTemplate = {
// ...
displayText: () => Blockly.Msg['MY_COLLAPSE_BLOCK_TEXT'],
// ...
};
หากใช้ฟังก์ชัน ระบบจะส่งค่า Scope
ไปให้ด้วย คุณใช้
พารามิเตอร์นี้เพื่อเพิ่มข้อมูลเกี่ยวกับองค์ประกอบลงในข้อความที่แสดงได้
const collapseTemplate = {
// ...
displayText: (scope) => {
if (scope.focusedNode instanceof Blockly.Block) {
return `Collapse ${scope.focusedNode.type} block`;
}
// Shouldn't be possible, as our preconditionFn only shows this item for blocks
return '';
},
// ...
}
น้ำหนัก
weight
จะกำหนดลำดับการแสดงรายการในเมนูตามบริบท
ค่าบวกที่มากกว่าจะแสดงในรายการต่ำกว่าค่าบวกที่น้อยกว่า
(คุณอาจจินตนาการได้ว่ารายการที่มีน้ำหนักสูงกว่าจะ "หนักกว่า" จึงจมลงไปที่ด้านล่าง)
const collapseTemplate = {
// ...
weight: 10,
// ...
}
น้ำหนักสำหรับรายการในเมนูตามบริบทในตัวจะเรียงตามลำดับจากน้อยไปมาก โดยเริ่มที่ 1 และเพิ่มขึ้นทีละ 1
ฟังก์ชัน Callback
พร็อพเพอร์ตี้ callback
เป็นฟังก์ชันที่ดำเนินการกับรายการในเมนูบริบท
โดยจะส่งพารามิเตอร์หลายรายการ ดังนี้
scope
: ออบเจ็กต์Scope
ที่ให้การอ้างอิงถึงคอมโพเนนต์ที่มีเมนูเปิดอยู่menuOpenEvent
:Event
ที่ทริกเกอร์การเปิดเมนูตามบริบท ซึ่งอาจเป็นPointerEvent
หรือKeyboardEvent
ขึ้นอยู่กับวิธีที่ผู้ใช้เปิดเมนูmenuSelectEvent
:Event
ที่เลือกรายการเมนูตามบริบทนี้จากเมนู ซึ่งอาจเป็นPointerEvent
หรือKeyboardEvent
ขึ้นอยู่กับวิธีที่ผู้ใช้เลือกรายการlocation
:Coordinate
ในพิกเซลพิกัด ที่เปิดเมนู ซึ่งช่วยให้คุณสร้างบล็อกใหม่ที่ตำแหน่งคลิกได้ เป็นต้น
const collapseTemplate = {
// ...
callback: (scope, menuOpenEvent, menuSelectEvent, location) => {
if (scope.focusedNode instanceof Blockly.BlockSvg) {
scope.focusedNode.collapse();
}
},
}
คุณใช้ scope
เพื่อออกแบบเทมเพลตที่ทำงานแตกต่างกันได้โดยขึ้นอยู่กับ
คอมโพเนนต์ที่เปิดเทมเพลต
const collapseTemplate = {
// ...
callback: (scope) => {
if (scope.focusedNode instance of Blockly.BlockSvg) {
// On a block, collapse just the block.
const block = scope.focusedNode;
block.collapse();
} else if (scope.focusedNode instanceof Blockly.WorkspaceSvg) {
// On a workspace, collapse all the blocks.
let workspace = scope.focusedNode;
collapseAllBlocks(workspace);
}
}
}
ตัวแบ่ง
separator
พร็อพเพอร์ตี้จะวาดเส้นในเมนูตามบริบท
เทมเพลตที่มีพร็อพเพอร์ตี้ separator
จะมีพร็อพเพอร์ตี้ preconditionFn
,
displayText
หรือ callback
ไม่ได้ และจะกำหนดขอบเขตได้ด้วยพร็อพเพอร์ตี้ scopeType
เท่านั้น ข้อจำกัดหลังหมายความว่าใช้ได้เฉพาะใน
เมนูบริบทสำหรับพื้นที่ทำงาน บล็อก และความคิดเห็นในพื้นที่ทำงาน
const separatorAfterCollapseBlockTemplate = {
id: 'separatorAfterCollapseBlock',
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
weight: 11, // Between the weights of the two items you want to separate.
separator: true,
};
คุณต้องมีเทมเพลตที่แตกต่างกันสำหรับตัวคั่นแต่ละตัวในเมนูบริบท ใช้พร็อพเพอร์ตี้
weight
เพื่อจัดตำแหน่งตัวคั่นแต่ละตัว
ประเภทขอบเขต
เลิกใช้งานพร็อพเพอร์ตี้ scopeType
แล้ว ก่อนหน้านี้ใช้เพื่อพิจารณาว่าควรแสดงรายการเมนูในเมนูตามบริบทสำหรับบล็อก ความคิดเห็นในพื้นที่ทำงาน
หรือพื้นที่ทำงานหรือไม่ เนื่องจากเปิดเมนูตามบริบทในคอมโพเนนต์อื่นๆ ได้ พร็อพเพอร์ตี้
scopeType
จึงจำกัดมากเกินไป แต่คุณควรใช้
preconditionFn
เพื่อแสดงหรือซ่อนตัวเลือกสำหรับคอมโพเนนต์ที่เกี่ยวข้อง
หากคุณมีเทมเพลตเมนูตามบริบทที่ใช้ scopeType
อยู่ Blockly จะ
แสดงรายการเฉพาะคอมโพเนนต์ที่เหมาะสมต่อไป
const collapseTemplate = {
// ...
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
// ...
};
ปรับแต่งรีจิสทรี
คุณสามารถเพิ่ม ลบ หรือแก้ไขเทมเพลตในรีจิสทรีได้ คุณดูเทมเพลตเริ่มต้นได้ใน contextmenu_items.ts
เพิ่มเทมเพลต
คุณเพิ่มเทมเพลตลงในรีจิสทรีได้โดยการลงทะเบียน คุณควรทำเช่นนี้ เมื่อโหลดหน้าเว็บ ซึ่งอาจเกิดขึ้นก่อนหรือหลังจากที่คุณแทรกพื้นที่ทำงาน
const collapseTemplate = { /* properties from above */ };
Blockly.ContextMenuRegistry.registry.register(collapseTemplate);
ลบเทมเพลต
คุณนำเทมเพลตออกจากรีจิสทรีได้โดยยกเลิกการลงทะเบียนตามรหัส
Blockly.ContextMenuRegistry.registry.unregister('someID');
แก้ไขเทมเพลต
คุณแก้ไขเทมเพลตที่มีอยู่ได้โดยรับเทมเพลตจากรีจิสทรี แล้วแก้ไขในตำแหน่ง
const template = Blockly.ContextMenuRegistry.registry.getItem('someID');
template?.displayText = 'some other display text';
ปิดใช้เมนูตามบริบทของฟีเจอร์บล็อก
โดยค่าเริ่มต้น บล็อกจะมีเมนูตามบริบทที่ช่วยให้ผู้ใช้ทำสิ่งต่างๆ ได้ เช่น เพิ่มความคิดเห็นในบล็อกหรือทำซ้ำบล็อก
คุณปิดใช้เมนูตามบริบทของบล็อกแต่ละรายการได้โดยทำดังนี้
block.contextMenu = false;
ในคำจำกัดความ JSON ของประเภทบล็อก ให้ใช้คีย์ enableContextMenu
{
// ...,
"enableContextMenu": false,
}
ปรับแต่งเมนูตามบริบทต่อประเภทบล็อกหรือพื้นที่ทำงาน
หลังจากที่ Blockly สร้างอาร์เรย์ของรายการเมนูบริบทแล้ว คุณจะปรับแต่งรายการดังกล่าวสำหรับบล็อกหรือพื้นที่ทำงานแต่ละรายการได้ โดยตั้งค่า BlockSvg.customContextMenu
หรือ
WorkspaceSvg.configureContextMenu
เป็นฟังก์ชันที่
แก้ไขอาร์เรย์ในตำแหน่ง
ออบเจ็กต์ในอาร์เรย์ที่ส่งไปยังบล็อกมีประเภท
ContextMenuOption
หรือใช้ส่วนติดต่อ
LegacyContextMenuOption
ออบเจ็กต์ที่ส่งไปยัง
พื้นที่ทํางานมีประเภท ContextMenuOption
Blockly ใช้พร็อพเพอร์ตี้ต่อไปนี้
จากออบเจ็กต์เหล่านี้
text
: ข้อความที่แสดงenabled
: หากfalse
ให้แสดงรายการด้วยข้อความสีเทาcallback
: ฟังก์ชันที่จะเรียกใช้เมื่อคลิกรายการseparator
: รายการนี้เป็นตัวคั่น ใช้ร่วมกับพร็อพเพอร์ตี้อีก 3 รายการไม่ได้
ดูเอกสารอ้างอิงสำหรับประเภทพร็อพเพอร์ตี้และลายเซ็นฟังก์ชัน
ตัวอย่างเช่น ฟังก์ชันต่อไปนี้จะเพิ่มรายการ Hello, World!
ลงในเมนูตามบริบทของพื้นที่ทํางาน
workspace.configureContextMenu = function (menuOptions, e) {
const item = {
text: 'Hello, World!',
enabled: true,
callback: function () {
alert('Hello, World!');
},
};
// Add the item to the end of the context menu.
menuOptions.push(item);
}
แสดงเมนูตามบริบทในออบเจ็กต์ที่กำหนดเอง
คุณสามารถทำให้เมนูบริบทปรากฏสำหรับคอมโพเนนต์ที่กำหนดเองได้โดยทำตามขั้นตอนต่อไปนี้
- ใช้
IFocusableNode
หรือขยายคลาสที่ใช้IFocusableNode
อินเทอร์เฟซนี้ใช้ในเมนูบริบทของระบบเพื่อระบุคอมโพเนนต์ นอกจากนี้ยังช่วยให้ผู้ใช้ ไปยังคอมโพเนนต์ของคุณได้โดยใช้ปลั๊กอินการนำทางด้วยแป้นพิมพ์ ใช้
IContextMenu
ซึ่งมีฟังก์ชันshowContextMenu
ฟังก์ชันนี้จะรับรายการเมนูตามบริบทจากรีจิสทรี คำนวณตำแหน่งบนหน้าจอที่จะแสดงเมนู และแสดงเมนูในที่สุดหากมีรายการที่จะแสดงconst MyBubble implements IFocusableNode, IContextMenu { ... showContextMenu(menuOpenEvent) { // Get the items from the context menu registry const scope = {focusedNode: this}; const items = Blockly.ContextMenuRegistry.registry.getContextMenuOptions(scope, menuOpenEvent); // Return early if there are no items available if (!items.length) return; // Show the menu at the same location on screen as this component // The location is in pixel coordinates, so translate from workspace coordinates const location = Blockly.utils.svgMath.wsToScreenCoordinates(new Coordinate(this.x, this.y)); // Show the context menu Blockly.ContextMenu.show(menuOpenEvent, items, this.workspace.RTL, this.workspace, location); } }
เพิ่มตัวแฮนเดิลเหตุการณ์ที่เรียกใช้
showContextMenu
เมื่อผู้ใช้คลิกขวาที่คอมโพเนนต์ โปรดทราบว่าปลั๊กอินการนำทางด้วยคีย์บอร์ดมีตัวแฮนเดิลเหตุการณ์ที่เรียกใช้showContextMenu
เมื่อผู้ใช้กดCtrl+Enter
(Windows) หรือCommand+Enter
(Mac)เพิ่มเทมเพลตลงในรีจิสทรีสำหรับรายการในเมนูบริบท