開發者嘗試為多個 .side-icon 元素綁定點擊事件,期望實現「點擊展開側邊欄,再次點擊收起」的切換效果。但實際運行時發現:點擊第一個圖標能展開,再次點擊卻無反應;此時點擊第二個圖標反而會觸發收起動作。邏輯明顯錯亂。
var sideRight = document.getElementById('sideright');
var side = document.getElementsByClassName('side-icon');
var flag = true; // 全域旗標
for (var i = 0; i < side.length; i++) {
(function() {
if (flag) {
side[i].addEventListener('click', function() {
changeManyElem(sideRight, {'right': 0}, 30);
}, false);
flag = false;
} else {
side[i].addEventListener('click', function() {
changeManyElem(sideRight, {'right': -350}, 30);
}, false);
flag = true;
}
})();
}
if (flag) 只在綁定事件的那一刻判斷一次,導致第一個元素綁定「展開」,第二個綁定「收起」,第三個又綁定「展開」……而非每個元素各自擁有獨立的切換狀態。flag:所有元素共用同一個旗標,無法記住各自的開合狀態。為每個元素綁定同一個點擊事件,在處理函式中根據當前狀態決定動作。狀態可儲存在元素的 dataset 或閉包中。
var sideRight = document.getElementById('sideright');
var icons = document.getElementsByClassName('side-icon');
for (var i = 0; i < icons.length; i++) {
// 使用閉包捕獲當前索引,或直接用 this
icons[i].addEventListener('click', function() {
// 從元素屬性讀取狀態,初始為 'closed'
var isOpen = this.dataset.state === 'open';
var targetRight = isOpen ? -350 : 0;
changeManyElem(sideRight, {'right': targetRight}, 30);
// 切換狀態
this.dataset.state = isOpen ? 'closed' : 'open';
}, false);
}
將動畫邏輯移至 CSS,JS 僅負責切換類別,職責分離更清晰。
/* CSS */
#sideright {
position: fixed;
right: -350px;
transition: right 0.3s ease;
}
#sideright.open {
right: 0;
}
/* JS */
var sideRight = document.getElementById('sideright');
var icons = document.getElementsByClassName('side-icon');
for (var i = 0; i < icons.length; i++) {
icons[i].addEventListener('click', function() {
sideRight.classList.toggle('open');
});
}
.toggle() 方法(舊版專用)若專案已使用 jQuery,可用 toggle(handler1, handler2)(注意:jQuery 1.9+ 已移除此簽名,需用 click 內部判斷)。
if)只會跑一次;真正的邏輯必須放在事件處理函式內部。dataset)、閉包或 WeakMap 維護各自狀態。var 無塊級作用域,若在迴圈中建立閉包需用 IIFE 傳入索引或改用 let(ES6)。