在電商商品頁或旅遊網站中,點擊小縮圖即時切換大圖是標準配備。但如果畫面上有幾十張圖片,每張都獨立綁定 Listener 會顯得冗長且佔用效能。今天我們就用「事件委派(Event Delegation)」來優化它。
thumbContainer 上,利用事件冒泡機制,透過 event.target.classList.contains('thumb') 精準捕捉子元素點擊。src 與 data-caption,直接覆寫大圖 DOM 的 src 與文字內容,搭配 CSS opacity 做出流暢的切換淡入效果。1. 事件委派(Event Delegation)與 event.target
為什麼選用這個架構?
如果縮圖區有 100 張圖片,為每張圖片單獨綁定 addEventListener 會消耗大量記憶體。
利用 DOM 的事件冒泡機制(Event Bubbling),我們只需要在外層容器(父元素)綁定 一個 點擊事件,就能監聽並處理所有內層縮圖的點擊!
這個機制在幹嘛?
當點擊縮圖時,點擊事件會向上冒泡傳到父容器。父容器透過 event.target 檢查:「剛才被點擊的到底是不是 <img> 標籤?」,如果是,才執行圖片切換邏輯。
2. 動態替換 DOM 屬性 (mainImg.src 與 mainImg.alt)
為什麼選用這個方式?
切換大圖不需要重新建立 DOM 元素,直接將縮圖上記錄的高清圖網址(或 src)與文字說明寫入大圖標籤的 src 與 alt 屬性即可,效能較高。
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<title>第十三課 - 動態圖片展示藝廊</title>
<style>
body { font-family: sans-serif; padding: 40px; background-color: #f5f5f5; }
.gallery-container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
/* 主圖顯示區塊 */
.main-image-container { width: 100%; height: 350px; overflow: hidden; border-radius: 8px; margin-bottom: 10px; background-color: #eee; }
.main-image { width: 100%; height: 100%; object-fit: cover; transition: opacity 0.3s ease; }
/* 圖片說明標題 */
.image-caption { font-size: 16px; font-weight: bold; color: #333; text-align: center; margin-bottom: 20px; }
/* 縮圖選單區塊 (父容器) */
.thumbnail-list { display: flex; gap: 10px; justify-content: center; }
/* 單張縮圖 */
.thumb {
width: 80px;
height: 60px;
object-fit: cover;
border-radius: 6px;
cursor: pointer;
opacity: 0.6;
border: 2px solid transparent;
transition: all 0.2s ease;
}
.thumb:hover { opacity: 0.9; }
/* 縮圖選取狀態 (Active) */
.thumb.active {
opacity: 1;
border-color: #007bff;
transform: scale(1.05);
}
</style>
</head>
<body>
<div class="gallery-container">
<!-- 大圖呈現區 -->
<div class="main-image-container">
<img id="mainImg" class="main-image" src="https://picsum.photos/id/1018/600/400" alt="高山湖泊風景">
</div>
<div id="imageCaption" class="image-caption">高山湖泊風景</div>
<!-- 縮圖列表 (使用事件委派:只在父容器綁定事件) -->
<div id="thumbContainer" class="thumbnail-list">
<img class="thumb active" src="https://picsum.photos/id/1018/600/400" data-caption="高山湖泊風景" alt="縮圖 1">
<img class="thumb" src="https://picsum.photos/id/1015/600/400" data-caption="壯麗河流峽谷" alt="縮圖 2">
<img class="thumb" src="https://picsum.photos/id/1019/600/400" data-caption="海邊晨曦曙光" alt="縮圖 3">
<img class="thumb" src="https://picsum.photos/id/1039/600/400" data-caption="瀑布森林秘境" alt="縮圖 4">
</div>
</div>
<script>
// ----------------------------------------------------
// JavaScript 邏輯 (圖片切換與事件委派)
// ----------------------------------------------------
// 第一步:取得大圖 DOM、標題 DOM 與縮圖父容器 DOM
const mainImg = document.getElementById("mainImg");
const imageCaption = document.getElementById("imageCaption");
const thumbContainer = document.getElementById("thumbContainer");
// 第二步:使用「事件委派」機制,將點擊事件綁定在縮圖的【父容器】上
thumbContainer.addEventListener("click", function(event) {
// 1. 檢查點擊的對象(event.target)是否為縮圖 (具有 .thumb 類別)
const clickedThumb = event.target;
if (!clickedThumb.classList.contains("thumb")) {
return; // 如果點擊的是父容器的空白處,直接結束不處理
}
// 2. 取得被點擊縮圖的圖片網址與自訂標題 (data-caption)
const newSrc = clickedThumb.src;
const newCaption = clickedThumb.dataset.caption;
// 3. 換圖淡出淡入視覺效果:先淡出,換網址後再淡入
mainImg.style.opacity = "0.3";
setTimeout(function() {
mainImg.src = newSrc;
mainImg.alt = newCaption;
imageCaption.innerText = newCaption;
mainImg.style.opacity = "1";
}, 150);
// 4. 排他思想:清空所有縮圖的 .active 類別,並為當前縮圖加上 .active
const allThumbs = thumbContainer.querySelectorAll(".thumb");
allThumbs.forEach(thumb => thumb.classList.remove("active"));
clickedThumb.classList.add("active");
});
</script>
</body>
</html>
今天我們掌握了「事件委派」這個前端優化的核心觀念,事件委派不僅能減少記憶體消耗,即使未來透過 API 畫面上動態「新增」了新縮圖,父容器依然能自動監控並處理它們的點擊。
在表單填寫或輸入搜尋關鍵字時,如果即時統計使用者輸入了多少字,該怎麼做?
【第十四課】表單與輸入:字數即時統計與限制告警(input 事件與雙向狀態),我們將學習如何掌控表單輸入事件與動態警告樣式。