我的目標是當我點選newbutton時,在自定義的areaDiv新增一次按鈕;
寫死的狀態下是可以做到只新增一次;
但後續想新增text、label...所以改成用參數傳遞。
發現無法取消Listener,請各大大幫我看一下出了甚麼問題?
原本程式碼:
newButton.addEventListener('click', function () {
if (!isDrawing) {
startX = 0;
startY = 0;
isDrawing = true;
areaDiv.addEventListener('mousedown', startSelection);
}
});
function startSelection(event) {
startX = event.clientX - areaDiv.offsetLeft;
startY = event.clientY - areaDiv.offsetTop;
isDrawing = true;
areaDiv.addEventListener('mousemove', updateSelection);
areaDiv.addEventListener('mouseup', createComponent);
}
function createComponent(event) {
if (isDrawing) {
var currentX = event.clientX - areaDiv.offsetLeft;
var currentY = event.clientY - areaDiv.offsetTop;
var width = Math.abs(currentX - startX);
var height = Math.abs(currentY - startY);
var left = Math.min(startX, currentX);
var top = Math.min(startY, currentY);
var newButton = document.createElement('button');
newButton.innerText = 'New Button';
newButton.style.position = 'absolute';
newButton.style.left = left + 'px';
newButton.style.top= top + 'px';
newButton.style.width = width + 'px';
newButton.style.height = height + 'px';
areaDiv.appendChild(newButton);
isDrawing = false;
areaDiv.removeEventListener('mousemove', updateSelection);
areaDiv.removeEventListener('mouseup', createComponent);
areaDiv.removeEventListener('mousedown', startSelection);
}
}
下面這是AI推薦寫法。
傳遞參數寫法:
newButton.addEventListener('click', function () {
if (!isDrawing) {
startX = 0;
startY = 0;
isDrawing = true;
areaDiv.addEventListener('mousedown', function(event) {
startSelection(event, 'button');
});
}
});
function startSelection(event, newcomponentType) {
startX = event.clientX - areaDiv.offsetLeft;
startY = event.clientY - areaDiv.offsetTop;
isDrawing = true;
areaDiv.addEventListener('mousemove', updateSelection);
areaDiv.addEventListener('mouseup', function(event) {
createComponent(event, newcomponentType);
});
}
function createComponent(event, newcomponentType) {
if (isDrawing) {
var currentX = event.clientX - areaDiv.offsetLeft;
var currentY = event.clientY - areaDiv.offsetTop;
var width = Math.abs(currentX - startX);
var height = Math.abs(currentY - startY);
var left = Math.min(startX, currentX);
var top = Math.min(startY, currentY);
if (newcomponentType === 'button') {
var newButton = document.createElement('button');
newButton.innerText = 'New Button';
newButton.style.position = 'absolute';
newButton.style.left = left + 'px';
newButton.style.top = top + 'px';
newButton.style.width = width + 'px';
newButton.style.height = height + 'px';
areaDiv.appendChild(newButton);
}
isDrawing = false;
areaDiv.removeEventListener('mouseup', createComponent);
areaDiv.removeEventListener('mousemove', updateSelection);
areaDiv.removeEventListener('mousedown', startSelection);
}
}
最後面有嘗試過下列寫法,一樣是無法取消
isDrawing = false;
areaDiv.removeEventListener('mousemove', updateSelection);
areaDiv.removeEventListener('mouseup', function(event) {
createComponent(event, newcomponentType);
});
areaDiv.removeEventListener('mousedown', function(event) {
startSelection(event, newcomponentType);
});
areaDiv.addEventListener('mousedown', function(event){})
因為你的新做法是用匿名函數處理事件,這種做法沒辦法removeEventListener。
如果要達成你要的功能,可以 button、text、label各寫一組function處理,或是用全域變數來傳遞參數。
感謝回答,但是我問題中的的寫法就是AI解決匿名函數寫法,
他當時也是說我是用匿名函數;但是AI的寫法無法處理這問題。
實際上我也不太懂那是啥意思。
我後來將程式重新改寫成
newButton.addEventListener('click', function() {
startSelection('button');
});
再來微調就OK了
這樣mousedown的部分就解決了,不過我很好奇你怎麼處理mouseup,可以的話能分享一下嗎?
老實說原理我也不太懂,程式上整體來說沒甚麼變,
主要是在startSelection中move & up寫到dowm內。
其實只要remove down listener就好,但是我有寫其他程式,
所以都要做移除動作。
newButton.addEventListener('click', function() {
startSelection('button');
});
function startSelection(type) {
componentType = type;
isDrawing = true;
areaDiv.addEventListener('mousedown', function(event) {
startX = event.clientX - areaDiv.offsetLeft;
startY = event.clientY - areaDiv.offsetTop;
areaDiv.addEventListener('mousemove', updateSelection);
areaDiv.addEventListener('mouseup', function(event) {
createComponent(event, componentType);
});
});
}
function createComponent(event, componentType) {
if (isDrawing) {
var currentX = event.clientX - areaDiv.offsetLeft;
var currentY = event.clientY - areaDiv.offsetTop;
var width = Math.abs(currentX - startX);
var height = Math.abs(currentY - startY);
var left = Math.min(startX, currentX);
var top = Math.min(startY, currentY);
if (componentType === 'button' || componentType === 'label') {
//省略
}
isDrawing = false;
componentType = null;
areaDiv.removeEventListener('mousemove', updateSelection);
areaDiv.removeEventListener('mouseup', createComponent);
areaDiv.removeEventListener('mousedown', startSelection);
if (areaDiv.contains(selectionDiv)) {
areaDiv.removeChild(selectionDiv);
}
}
}
現在解決後GPT的事後諸葛表示。
程式二可以使用removeEventListener方法,而程式一不行的原因是因為事件監聽器在每次點擊事件觸發後都會重新創建。
在程式一中,每次點擊newButton後,都會創建一個新的mousedown事件監聽器,並將其添加到areaDiv上。這導致areaDiv上存在多個相同的mousedown事件監聽器。當你嘗試使用areaDiv.removeEventListener來移除事件監聽器時,它只會移除最後一次添加的事件監聽器,而不是你期望的那個。
相反,在程式二中,只有一個mousedown事件監聽器被添加到areaDiv上,並在每次點擊newButton時都保持不變。因此,當你使用areaDiv.removeEventListener來移除事件監聽器時,它能正確地移除該事件監聽器。
要解決程式一中無法正確移除事件監聽器的問題,你可以將事件監聽器定義為具名函式,然後在需要移除它時使用相同的函式名稱來移除。這樣就可以避免重複添加事件監聽器的問題。