前言
在許多網頁應用中,常見的 UI 元件之一是 Tab 切換功能,讓使用者能在同一區塊內切換不同內容面板。這段程式碼示範如何用純 JavaScript 實作按鈕控制多個 Tab 面板的顯示與隱藏,適合有基礎 DOM 操作經驗,想了解如何手動管理元素狀態的前端工程師或自學者。
按鈕與面板元素的選取
首先,程式碼透過 document.querySelectorAll 分別取得所有具有 .action-btn 與 .tab-panel 類別的元素。這兩組元素分別代表切換按鈕與對應的內容面板。若任一組元素不存在,則直接結束執行,避免後續錯誤。
const buttons = document.querySelectorAll('.action-btn');
const panels = document.querySelectorAll('.tab-panel');
if (!buttons.length || !panels.length) return;
activateButton 函式設計
activateButton 是核心函式,負責切換按鈕的「活躍」狀態與對應面板的顯示。它透過按鈕的 data-target 屬性取得目標面板的類別名稱,並依序執行:
- 移除所有按鈕的
is-active樣式,確保只有一個按鈕處於活躍狀態。 - 為當前按鈕加上
is-active樣式。 - 隱藏所有面板(移除
is-active樣式)。 - 顯示對應目標面板(可支援多個面板同時顯示),加上
is-active樣式。
這種設計讓按鈕與面板的關聯透過 CSS 類別靈活控制,方便樣式調整與擴充。
function activateButton(btn) {
const target = btn.dataset.target;
if (!target) return;
buttons.forEach(b => b.classList.remove('is-active'));
btn.classList.add('is-active');
panels.forEach(p => p.classList.remove('is-active'));
const targetPanels = document.querySelectorAll('.' + target);
targetPanels.forEach(p => p.classList.add('is-active'));
}
綁定事件與初始化
接著,為每個按鈕綁定點擊事件,點擊時呼叫 activateButton,並阻止預設行為(例如連結跳轉)。
最後,為了讓頁面載入時即有預設顯示的面板,程式碼自動觸發第一個按鈕的點擊事件,確保初始化狀態與使用者互動完全一致,避免手動設定狀態可能導致的不同步問題。
buttons.forEach(btn => {
btn.addEventListener('click', e => {
e.preventDefault();
activateButton(btn);
});
});
buttons[0].click();
實務應用與延伸
這種純前端的 Tab 切換實作適合用於靜態頁面或不依賴框架的專案。若需要支援動態面板內容或更複雜的狀態管理,可考慮結合前端框架或狀態管理工具。
此外,為提升無障礙性,可在按鈕加入 ARIA 屬性,並確保鍵盤操作友好。
常見問題與注意事項
- 確保每個按鈕的
data-target對應的面板類別名稱正確,否則無法正確顯示。 - 若有多個面板共用同一類別,會同時顯示,這是設計上的彈性,但需注意樣式與結構。
- 自動觸發點擊事件的做法雖方便,但若未考慮瀏覽器支援或其他腳本,可能會有兼容性問題。
完整程式碼
document.addEventListener('DOMContentLoaded', function () {
const buttons = document.querySelectorAll('.action-btn');
const panels = document.querySelectorAll('.tab-panel');
if (!buttons.length || !panels.length) return;
function activateButton(btn) {
const target = btn.dataset.target;
if (!target) return;
buttons.forEach(function (b) {
b.classList.remove('is-active');
});
btn.classList.add('is-active');
panels.forEach(function (p) {
p.classList.remove('is-active');
});
const targetPanels = document.querySelectorAll('.' + target);
targetPanels.forEach(function (p) {
p.classList.add('is-active');
});
}
buttons.forEach(function (btn) {
btn.addEventListener('click', function (e) {
e.preventDefault();
activateButton(btn);
});
});
buttons[0].click();
});