Một câu hỏi thường gặp là cách sửa đổi định nghĩa của một khối hiện có. Ví dụ: bạn có thể muốn thêm tính năng kiểm tra kết nối hoặc thay đổi một trường thành dữ liệu đầu vào giá trị.
Nhìn chung, bạn không thể sửa đổi định nghĩa khối tại chỗ.
Cách sửa đổi định nghĩa hiện có
Nếu bạn muốn sửa đổi định nghĩa của một loại khối hiện có:
- Sao chép định nghĩa hiện có, bao gồm cả trình tạo mã khối.
- Sửa đổi bản sao và đặt tên mới cho loại của bạn.
- Thêm định nghĩa mới vào
Blockly.Blocks
.
Tại sao tôi không thể trực tiếp sửa đổi định nghĩa hiện có?
Nếu bạn muốn biết lý do không thể sửa đổi định nghĩa hiện có, hãy đọc tiếp. Chúng ta sẽ xem xét một số khả năng.
Sửa đổi trực tiếp định nghĩa hiện có
Có hai cách để sửa đổi trực tiếp định nghĩa của một khối hiện có: chèn mã và phân nhánh mã. Bạn không nên làm cả hai việc này vì bạn có nguy cơ làm hỏng mã phụ thuộc vào mã được vá hoặc mã được phân nhánh. Cả hai kỹ thuật này cũng gây khó khăn cho việc tích hợp bản cập nhật và bản sửa lỗi. Để biết thêm thông tin, hãy xem phần Monkeypatching là gì? và Fork Blockly.
Lớp con của một định nghĩa hiện có
Bạn có thể sẽ phải tạo lớp con cho một định nghĩa hiện có theo cách nào đó. Rất tiếc, bạn không thể làm như vậy vì các định nghĩa khối không phải là lớp mà là các thành phần kết hợp.
Ví dụ: không có cách nào để ghi đè thuộc tính màu vì định nghĩa không có thuộc tính màu. Thay vào đó, lớp này có một hàm init
gọi setColour
để đặt thuộc tính màu trên khối. Vì lệnh gọi nằm bên trong init
, nên không có cách nào để thay thế lệnh gọi đó mà không thay thế toàn bộ hàm init
.
Ghi đè hàm trong định nghĩa hiện có
Bạn có thể ghi đè một hàm trong định nghĩa hiện có:
Blockly.Blocks['existing_block'].init = function() {/*new function*/};
Cách này hoạt động, nhưng bạn phải sao chép và sửa đổi hàm hiện có – bạn không thể chỉ thay thế một dòng một cách kỳ diệu. Có một vài vấn đề với phương pháp này:
- Cách này không khác nhiều so với việc sao chép và sửa đổi toàn bộ định nghĩa.
- Bạn không thể sử dụng hàm này để sửa đổi hàm
init
của các khối được xác định trong JSON, chẳng hạn như các khối tích hợp sẵn của Blockly. Điều này là do không có hàminit
để sao chép – hàm này được tạo trong thời gian chạy. - Phương thức này yêu cầu bạn xác định khối bằng JavaScript, điều này có thể gây ra vấn đề về bản địa hoá.
Ghi đè kết quả của init
Một cách để "chỉ thay thế một dòng" của hàm init
là thay thế hàm init
bằng một hàm gọi hàm init
ban đầu, sau đó ghi đè kết quả của lệnh gọi đó. Ví dụ: mã sau đây sẽ thay đổi màu của khối logic_null
:
const originalInit = Blockly.Blocks['logic_null'].init;
Blockly.Blocks['logic_null'].init = function() {
originalInit.call(this);
this.setColour(300);
}
Rất tiếc, cách này không hữu ích như bạn nghĩ. Ví dụ:
Việc mở rộng quy trình kiểm tra kết nối hoặc áp dụng trình xác thực trường ít hạn chế hơn có thể làm mất hiệu lực các giả định do trình tạo mã khối và trình xử lý sự kiện đưa ra.
Việc thay thế một trường bằng dữ liệu đầu vào giá trị sẽ làm hỏng trình tạo mã khối và trình xác thực trường, đồng thời có thể làm hỏng trình xử lý sự kiện. Việc này cũng có thể cực kỳ khó thực hiện đối với các khối đã bản địa hoá vì các ngôn ngữ khác nhau có thể dẫn đến các khối có các loại và thứ tự đầu vào và trường khác nhau.
Ghi đè một cặp khoá-giá trị trong định nghĩa JSON
Nếu JSON cho một khối được cung cấp công khai, thì bạn có thể ghi đè các giá trị JSON riêng lẻ. Ví dụ:
// Block definition.
blockJson = {...};
Blockly.Blocks['my_block'] = {
init: function() {
initJson(blockJson); // Called when the block is created.
}
}
// Third-party code.
blockJson.colour = 100;
Tuy nhiên, điều này chỉ hoạt động nếu đối tượng JSON được cung cấp công khai, định nghĩa xác định rõ ràng hàm init
và hàm init
gọi initJson
. Phương thức này sẽ không hoạt động nếu JSON được truyền đến defineBlocksWithJsonArray
hoặc createBlockDefinitionsFromJsonArray
vì JSON được xử lý trước khi bên thứ ba có cơ hội sửa đổi JSON đó. (Lưu ý rằng các khối tích hợp của Blockly sử dụng createBlockDefinitionsFromJsonArray
.)
Nhưng nếu JSON không được xác định theo cách này thì sao? Tôi vẫn có thể ghi đè các thuộc tính JSON chứ? Rất tiếc là không. Định nghĩa này chứa một hàm init
(không phải JSON) và không có hàm nào để chuyển đổi hàm init
thành JSON.
// Doesn't work. There is no getJson() function.
const json = Blockly.Blocks['existing_block'].getJson();
json['message0'] = 'my new message0';
Blockly.Blocks['existing_block'].init = function () {
initJson(json);
};
Thiết kế để sử dụng lại
Khi thiết kế các khối tuỳ chỉnh của riêng mình, bạn có thể thiết kế các khối đó theo cách thúc đẩy việc sử dụng lại.
Sử dụng lại JSON
Nếu có hai khối tương tự nhau về cơ bản, bạn có thể tạo một định nghĩa JSON mẹ và sử dụng lại định nghĩa này trong các định nghĩa con. Ví dụ:
const parentJson = {
// shared properties
};
Blockly.Blocks['child_block_1'] = {
init: function() {
initJson({...parentJson, colour: 100})
}
}
Blockly.Blocks['child_block_2'] = {
init: function() {
initJson({...parentJson, colour: 200})
}
}
Một cách khác là xác định JSON trong một đối tượng có sẵn công khai và truyền đối tượng đó đến initJson
trong hàm init
. Điều này cho phép người khác ghi đè từng thuộc tính. Để biết thêm thông tin, hãy xem phần Ghi đè cặp khoá-giá trị trong định nghĩa JSON.
Sử dụng lại hàm
Khối có thể xác định một số hàm tiêu chuẩn, chẳng hạn như trình xử lý sự kiện cấp khối, chú giải công cụ tuỳ chỉnh, trình xác thực trường và các hàm mà đối tượng sửa đổi sử dụng, cũng như các hàm cung cấp hành vi tuỳ chỉnh, chẳng hạn như hàm đặt giá trị trường từ dữ liệu bên ngoài, chẳng hạn như vị trí hiện tại của cánh tay robot.
Bạn có thể sử dụng lại các hàm này trên các khối.
Sử dụng trường thả xuống
Nếu có một tập hợp các khối giống nhau về cơ bản ngoại trừ một toán tử, bạn có thể thiết kế một khối duy nhất có trường thả xuống cho toán tử đó. Ví dụ:
- Khối
logic_operation
tích hợp sử dụng trình đơn thả xuống với các toán tửand
vàor
. - Khối
math_arithmetic
tích hợp sử dụng trình đơn thả xuống có các toán tử+
,-
,×
,÷
và^
.
Việc viết trình tạo mã cho các khối như vậy thường phức tạp hơn một chút, nhưng vẫn dễ dàng hơn so với việc viết và duy trì nhiều khối.
Sử dụng phương thức sửa đổi
Nếu có một tập hợp các khối đại diện cho nhiều biến thể của cùng một cấu trúc lập trình, thì bạn có thể tạo một khối duy nhất sử dụng trình sửa đổi. Ví dụ: khối controls_if
tích hợp có thể đại diện cho nhiều biến thể của câu lệnh if-then-else
.