用 JavaScript 實作圖片縮圖點擊切換與自動輪播功能

前言

這段程式碼解決了圖片縮圖點擊切換主圖與自動輪播的需求,適合需要在產品展示或相簿頁面實作圖片瀏覽功能的前端工程師與自學者。透過純 JavaScript 控制圖片切換與輪播,避免依賴第三方套件,方便客製化與維護。

主要功能說明

取得縮圖與主圖元素

程式碼一開始透過 document.querySelectorAll 抓取所有縮圖元素 .gs-thumb,以及主圖容器 .gs-main-image,確保兩者存在後才繼續執行。這樣避免因為元素不存在導致錯誤。

const thumbs = Array.from(document.querySelectorAll('.gs-thumb'));
const mainPicture = document.querySelector('.gs-main-image');
if (!thumbs.length || !mainPicture) return;

初始化目前索引

先尋找哪個縮圖有 .active 樣式,代表當前顯示的圖片索引,若無則預設為 0。這樣設計方便在 HTML 中預先設定初始狀態。

let currentIndex = thumbs.findIndex(t => t.classList.contains('active'));
if (currentIndex === -1) currentIndex = 0;

切換主圖與縮圖的 active 樣式

showThumb 函式負責切換主圖與縮圖的狀態。它會從指定索引的縮圖抓取圖片路徑與 WebP 格式的 srcset,更新主圖的 <img><source> 標籤。

為了增加過場動畫效果,對主圖 <img> 加上 switching class,150 毫秒後移除,讓 CSS 可以控制淡入淡出等動畫。

最後將所有縮圖的 .active 移除,並將目前的縮圖加上 .active,同步視覺狀態。

function showThumb(index) {
  const picture = thumbs[index];
  if (!picture) return;

  const thumbImg = picture.querySelector('img');
  if (!thumbImg) return;

  const newSrc = thumbImg.getAttribute('src');
  const newWebp = picture.querySelector('source')?.getAttribute('srcset') || '';

  if (mainSource && newWebp) {
    mainSource.setAttribute('srcset', newWebp);
  }

  if (mainImg && newSrc) {
    mainImg.classList.add('switching');
    mainImg.setAttribute('src', newSrc);
    setTimeout(() => {
      mainImg.classList.remove('switching');
    }, 150);
  }

  thumbs.forEach(el => el.classList.remove('active'));
  picture.classList.add('active');

  currentIndex = index;
}

自動輪播機制

startAutoplay 使用 setInterval 每 3 秒自動切換到下一張縮圖,並呼叫 showThumb 更新主圖。索引會循環回到第一張,確保輪播無限循環。

resetAutoplay 則在使用者點擊縮圖時清除舊的計時器並重新啟動,避免自動輪播與手動操作衝突。

function startAutoplay() {
  autoplayTimer = setInterval(() => {
    const nextIndex = (currentIndex + 1) % thumbs.length;
    showThumb(nextIndex);
  }, 3000);
}

function resetAutoplay() {
  if (autoplayTimer) clearInterval(autoplayTimer);
  startAutoplay();
}

點擊縮圖切換邏輯

監聽整個文件的點擊事件,判斷點擊目標是否在 .gs-thumb 元素內,若是則取得該縮圖索引,呼叫 showThumb 切換主圖,並重置自動輪播計時。

這樣的事件代理方式有效減少監聽器數量,也方便動態新增縮圖時仍能正常運作。

document.addEventListener('click', function (e) {
  const picture = e.target.closest('.gs-thumb');
  if (!picture) return;

  const index = thumbs.indexOf(picture);
  if (index === -1) return;

  showThumb(index);
  resetAutoplay();
});

實務應用與優化方向

  • 可結合 CSS 進行更豐富的過場動畫,如淡入淡出、縮放等。
  • 若圖片數量龐大,考慮加入懶加載以提升效能。
  • 自動輪播時間可改為參數化,讓使用者自訂。
  • 可增加鍵盤左右鍵切換支援,提升無障礙。
  • 若需支援觸控裝置,加入滑動手勢切換功能。

完整程式碼

document.addEventListener('DOMContentLoaded', function () {
  const thumbs = Array.from(document.querySelectorAll('.gs-thumb'));
  const mainPicture = document.querySelector('.gs-main-image');
  if (!thumbs.length || !mainPicture) return;

  const mainImg = mainPicture.querySelector('img');
  const mainSource = mainPicture.querySelector('source');

  let currentIndex = thumbs.findIndex(t => t.classList.contains('active'));
  if (currentIndex === -1) currentIndex = 0;

  let autoplayTimer = null;

  function showThumb(index) {
    const picture = thumbs[index];
    if (!picture) return;

    const thumbImg = picture.querySelector('img');
    if (!thumbImg) return;

    const newSrc = thumbImg.getAttribute('src');
    const newWebp = picture.querySelector('source')?.getAttribute('srcset') || '';

    if (mainSource && newWebp) {
      mainSource.setAttribute('srcset', newWebp);
    }

    if (mainImg && newSrc) {
      mainImg.classList.add('switching');
      mainImg.setAttribute('src', newSrc);
      setTimeout(() => {
        mainImg.classList.remove('switching');
      }, 150);
    }

    thumbs.forEach(el => el.classList.remove('active'));
    picture.classList.add('active');

    currentIndex = index;
  }

  function startAutoplay() {
    autoplayTimer = setInterval(() => {
      const nextIndex = (currentIndex + 1) % thumbs.length;
      showThumb(nextIndex);
    }, 3000);
  }

  function resetAutoplay() {
    if (autoplayTimer) clearInterval(autoplayTimer);
    startAutoplay();
  }

  document.addEventListener('click', function (e) {
    const picture = e.target.closest('.gs-thumb');
    if (!picture) return;

    const index = thumbs.indexOf(picture);
    if (index === -1) return;

    showThumb(index);
    resetAutoplay();
  });

  showThumb(currentIndex);
  startAutoplay();
});