JavaScript 點擊與滑鼠事件的異常處理:問題分析與優化過程
更新日期: 2024 年 11 月 11 日
在這篇文章中,我們將詳細介紹 JavaScript 中 click、mouseenter 和 mouseleave 事件的衝突問題,並探討多個修正過程中遇到的異常,最終提供有效解決方案。
本文會分別展示初始代碼和修改後的代碼,並逐步分析其異常原因。
問題描述
我們的目標是實現一組按鈕,每個按鈕在滑鼠移入(mouseenter)時變色,滑鼠移出(mouseleave)時恢復初始顏色。
當按鈕被點擊後,希望它保持選中樣式,不再受滑鼠移入移出事件影響。
然而,原始代碼未能成功達到這一效果。
初始代碼
以下是第一版的代碼,它使用 click 事件改變按鈕樣式,但無法防止 mouseleave 重設樣式:
const bannerMenu = document.querySelector(".banner_menu");
const bannerImgOutsideBackground = document.querySelector(".banner_img-outsideBackground img");
const bannerImgInside = document.querySelector(".banner_img-inside img");
const bannerLink = document.querySelector(".banner_img-inside a");
const bannerImg = { /* 圖片資料物件 */ }
const bannerLinkGroup = { /* 連結資料物件 */ }
const listGroup = bannerMenu.children;
bannerMenu.addEventListener("click", (e) => {
for (let i = 0; i < listGroup.length; i++) {
listGroup[i].style.background = 'rgb(148 163 184 / 0.3)';
listGroup[i].style.color = 'inherit';
}
bannerImgOutsideBackground.src = bannerImg[e.target.innerText];
bannerImgInside.src = bannerImg[e.target.innerText];
bannerLink.href = bannerLinkGroup[e.target.innerText];
e.target.style.background = '#ff133e';
e.target.style.color = '#FFF';
})
for (let i = 0; i < listGroup.length; i++) {
if(listGroup[i].style.background === '#ff133e' ){
continue;
}
listGroup[i].addEventListener("mouseenter", () => {
listGroup[i].style.background = '#29303e';
listGroup[i].style.color = '#FFF';
})
listGroup[i].addEventListener("mouseleave", () => {
listGroup[i].style.background = 'rgb(148 163 184 / 0.3)';
listGroup[i].style.color = 'inherit';
})
}
初始代碼的異常之處
- 無法判斷點擊狀態:
listGroup[i].style.background === '#ff133e'
判斷無效。瀏覽器可能將顏色自動轉換為rgb(255, 19, 62)
,導致比較失敗。 - mouseleave 事件覆蓋樣式:mouseenter 和 mouseleave 事件未檢查元素是否被點擊,無論點擊與否,mouseleave 都會重設樣式,造成點擊後的樣式被覆蓋。
- 初始判斷放置位置不佳:
style.background
的判斷僅在 迴圈安裝監聽器時運行,並未動態檢查 mouseenter 和 mouseleave 的每次變動。 - 靜態條件檢查無法應對動態需求:初始設定
style.background
的位置導致判斷在事件觸發時無法準確反映最新狀態。
最終解決方案
根據以上分析,我們在最終版中採用如下改進方案:
- 使用
dataset
屬性進行狀態標記:不再依賴style.background
或activeElement
判斷,而是通過dataset.status
屬性追蹤按鈕狀態: - dataset 設置在 click 事件中:每次點擊都重設未點擊按鈕的
dataset.status
為default
,並將當前點擊按鈕設為active
。 - mouseenter 和 mouseleave 動態檢查:在每次 mouseenter 和 mouseleave 事件中動態檢查
dataset.status
是否為active
,以確保點擊的按鈕不受影響。
最終版的代碼如下:
bannerMenu.addEventListener("click", (e) => {
for (let i = 0; i < listGroup.length; i++) {
listGroup[i].style.background = 'rgb(148 163 184 / 0.3)';
listGroup[i].style.color = 'inherit';
listGroup[i].dataset.status = "default"; // 設置默認狀態
}
bannerImgOutsideBackground.src = bannerImg[e.target.innerText];
bannerImgInside.src = bannerImg[e.target.innerText];
bannerLink.href = bannerLinkGroup[e.target.innerText];
e.target.style.background = '#ff133e';
e.target.style.color = '#FFF';
e.target.dataset.status = "active"; // 設置點擊狀態
});
for (let i = 0; i < listGroup.length; i++) {
listGroup[i].addEventListener("mouseenter", () => {
if (listGroup[i].dataset.status === 'active') return; // 跳過已點擊的元素
listGroup[i].style.background = '#29303e';
listGroup[i].style.color = '#FFF';
});
listGroup[i].addEventListener("mouseleave", () => {
if (listGroup[i].dataset.status === 'active') return; // 跳過已點擊的元素
listGroup[i].style.background = 'rgb(148 163 184 / 0.3)';
listGroup[i].style.color = 'inherit';
});
}
解決成果
- 滑鼠事件檢查點擊狀態:每次 mouseenter 和 mouseleave 事件都檢查
dataset.status
是否為active
,保證點擊後的按鈕不會被 mouseleave 覆蓋。 - 狀態跟蹤準確:使用
dataset
狀態標記確保每個按鈕的點擊和非點擊狀態能夠被準確區分。
結語
透過多次優化,我們成功解決了 click、mouseenter 和 mouseleave 事件的樣式覆蓋問題。
每次修改都基於更深入的理解和逐步檢查的思路,確保代碼最終能穩定實現預期功能。