Open ianfun opened 11 months ago
另外,我想提一些建議
innerHTML
,因為這要經過parse HTML->DOM的過程,可以用 DOM 的 appendChild
之類的來達成eleemnt.style.verticalAlign = 'middle'
等達成如 this.imageElement_.innerHTML = highLight.join("<br>");
等,可能會造成使用上的延遲。更好的作法是直接修改那個 element 的 style 而不是直接替換 HTML
例如
dropdownCreate_() {
this.imageElement_ = document.createElement('div');
this.imageElement_.style.padding = this.divPadding;
this.imageElement_.style.height = this.divHeight;
this.imageElement_ .style.width = this.divWidth;
this.imageElement_.style.fontSize = this.textSize;
this.imageElement_.style.whiteSpace = 'nowrap';
this.showList = [];
for (const X of this.originList) {
const d = document.createElement('div');
const x = new Image(this.imageSize, this.imageSize);
x.style.verticalAlign = 'middle';
x.src = X[1];
const y = document.createElement('span');
y.textContent = X[0];
y.style.float = 'right';
d.appendChild(x);
d.appendChild(y);
this.imageElement_.appendChild(d);
}
return this.imageElement_;
}
可以添加class讓它更像原本的樣式
dropdownCreate_(div) {
for (const X of this.originList) {
const d = document.createElement('div');
const x = new Image(this.imageSize, this.imageSize);
x.style.verticalAlign = 'middle';
x.src = X[1];
const y = document.createElement('span');
y.textContent = X[0];
y.style.float = 'right';
d.appendChild(x);
d.appendChild(y);
d.classList.add('blocklyDropdownMenu', 'blocklyMenuItem');
d.onpointerover = function() {
d.classList.add('blocklyMenuItemHighlight');
}
d.onpointerleave = function() {
d.classList.remove('blocklyMenuItemHighlight');
}
div.appendChild(d);
}
}
onclick
, onmouseover
等其實也可以直接綁定在 child 裡,這樣就不用計算高度等
我不知道為什麼不能連續選擇
以下是測試用版本
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Blockly Demo</title>
<script src="https://unpkg.com/blockly/blockly_compressed.js"></script>
<script src="https://unpkg.com/blockly/blocks_compressed.js"></script>
<script src="https://unpkg.com/blockly/msg/zh-hant.js"></script>
</head>
<body>
<style>
body, html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.blocklyMenuItemSelected .blocklyMenuItemCheckbox {
position: absolute !important;
}
</style>
<div id="blocklyDiv" style="height: 100%; width: 100%;"></div>
<script>
var toolbox = {
"kind": "categoryToolbox",
"contents": [
{
"kind": "category",
"name": "TEST",
"categorystyle": "logic_category",
"contents": [{
"kind": "block",
"type": "TEST1"
},
{
"kind": "block",
"type": "math_constant"
}
]
}
]
}
window.onload = function() {
class ImageTextDropDown extends Blockly.FieldTextInput {
constructor(text, options) {
super(Blockly.Field.SKIP_SETUP);
this.opt = options;
this.setSpellcheck(false);
}
fromJson() {
return new ImageTextDropDown(this.options['FieldsImageDropdown']);
}
showEditor_(e) {
super.showEditor_(this, e, true);
this.htmlInput_.disabled = true;
var div = Blockly.WidgetDiv.getDiv();
if (!div.firstChild) {
return;
}
this.dropdownCreate_(Blockly.DropDownDiv.getContentDiv());
Blockly.DropDownDiv.showPositionedByField(this);
}
dropdownCreate_(div) {
const cur = this.getValue() || 0;
div.style.paddingLeft = '30px';
const self = this;
let i = 0;
for (const X of this.opt) {
const d = document.createElement('div');
const D = document.createElement('div');
const x = new Image(24, 24);
x.src = X[1];
const y = document.createElement('span');
y.style.marginLeft = '1em';
y.textContent = X[0];
y.style.float = 'right';
const check = document.createElement('div');
check.classList.add('blocklyMenuItemCheckbox', 'goog-menuitem-checkbox');
D.appendChild(check);
D.style.display = 'flex';
D.style.alignItems = 'center';
D.appendChild(x);
D.appendChild(y);
D.classList.add('blocklyMenuItemContent', 'goog-menuitem-content');
d.classList.add('blocklyDropdownMenu', 'blocklyMenuItem');
if (i == cur)
d.classList.add('blocklyMenuItemSelected');
// https://github.com/google/blockly/blob/dc61e487b4e0024a53866e8aff652c0b108a0340/core/menu.ts#L102
d.onpointerenter = function(event) {
event.currentTarget.focus();
}
d.onpointerover = function() {
d.classList.add('blocklyMenuItemHighlight');
}
d.onpointerleave = function() {
d.classList.remove('blocklyMenuItemHighlight');
}
d.onpointerup = function(event) {
self.setEditorValue_(event.currentTarget.i);
Blockly.DropDownDiv.hide();
}
d.appendChild(D);
div.appendChild(d);
d.i = i;
++i;
}
}
valueToText(value) {
return this.opt[Number(value)][0];
}
textToValue(text) {
for (let i = 0;i < this.opt.length;++i) {
if (this.opt[i][0] == text)
return i;
}
return -1;
}
getText_() {
if (this.isBeingEdited_)
return super.getText_();
return this.opt[this.getValue() || 0][0];
}
getEditorText_(value) {
return this.valueToText(value);
}
getValueFromEditorText_(text) {
return this.textToValue(text);
}
doClassValidation_(opt_newValue) {
return;
}
}
Blockly.Blocks["TEST1"] = {
init: function() {
var options = [
['CLOUDY', "https://imgur.com/Hi33BEx.png", "ccc"],
['PARTLY-CLOUDY', "https://imgur.com/rX0np7I.png", "ppp"],
['MOON', "https://imgur.com/ulJIWW4.png", "mmm"],
['RAIN', "https://imgur.com/wRwu4pZ.png", "rrr"],
['STAR', "https://imgur.com/KMWOcGf.png", "sss"]
];
var dropdownWidth = 200;
var dropdownHeight = 100;
var imageField = new Blockly.FieldImage(options[0][1], 18, 18, {
alt: "*",
flipRtl: "FALSE"
});
var field = new ImageTextDropDown('', options, this.validate, dropdownWidth, dropdownHeight, imageField);
this.appendDummyInput()
.appendField(imageField, "i");
this.appendDummyInput()
.appendField(field, 'd');
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(100);
}
};
const workspace = Blockly.inject('blocklyDiv', {
toolbox: toolbox
});
};
</script>
</body>
</html>
謝謝您提供了寶貴的建議,我測試了您改寫的程式碼並比對了我原本的程式碼,這問題有可能是您省略了少部分看似不必要的函式造成,我會再另找時間測試。
Blockly似乎建議我們使用 class 而不是 function 的物件導向寫法
我看了 Blockly 的文件,
Blockly.utils.object.inherits
和googl.inherits
似乎都被移除了以 fuFieldsImageDropdown 為例,程式應該長這樣
class的寫法不僅易讀,也符合Javascript的趨勢