原代碼問題
- 邏輯錯誤:
if (!isShow) ... else ... 但 isShow 未在 else 分支重置。
- 全局變量污染,多實例衝突。
現代最佳實踐
<div id="trigger">點我展開/收起</div>
<div id="target" style="display:none">我是要展開的對象或收起的對象</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const trigger = document.getElementById('trigger');
const target = document.getElementById('target');
trigger.addEventListener('click', () => {
// 核心:根據當前 display 狀態切換
target.style.display = target.style.display === 'none' ? 'block' : 'none';
// 或使用 class 切換 (推薦,樣式與行為分離)
// target.classList.toggle('hidden');
});
});
</script>
<style>
.hidden { display: none; }
</style>
進階:動畫過渡 (CSS)
<style>
#target {
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.3s ease, opacity 0.3s ease;
}
#target.visible {
max-height: 500px; /* 足夠大的值 */
opacity: 1;
}
</style>
<script>
trigger.addEventListener('click', () => target.classList.toggle('visible'));
</script>
多實例通用組件 (Vanilla JS)
class TogglePanel {
constructor(triggerSelector, targetSelector) {
this.trigger = document.querySelector(triggerSelector);
this.target = document.querySelector(targetSelector);
this.trigger.addEventListener('click', () => this.toggle());
}
toggle() {
this.target.hidden = !this.target.hidden; // HTML5 hidden 屬性,無需 CSS
}
}
// 使用
new TogglePanel('#btn1', '#panel1');
new TogglePanel('#btn2', '#panel2');
避坑指南
- **不要用內聯
onclick="..."**,難以維護、CSP 限制。
- **優先用
hidden 屬性或 CSS class**,而非直接操作 style.display,便於動畫、響應式。
- 無障礙:添加
aria-expanded、aria-controls 屬性。