首頁  >  文章  >  web前端  >  使用 Svelte 建立動態影像網格:實現翻轉卡過渡

使用 Svelte 建立動態影像網格:實現翻轉卡過渡

Barbara Streisand
Barbara Streisand原創
2024-11-25 05:20:17149瀏覽

Building a dynamic image grid with Svelte: implementing flip card transitions

創造引人入勝的使用者介面通常需要在功能和視覺吸引力之間取得微妙的平衡。在本文中,我們將探索如何使用 Svelte 建立動態影像網格元件,該元件不僅可以有效管理狀態,而且可以在影像換入和換出時提供平滑、引人注目的過渡。

願景

想像一個定期刷新自身的影像網格,各個卡片平滑地翻轉以顯示新影像。

這創建了一個引人入勝的顯示,非常適合展示團隊成員、產品目錄或任何大於一次顯示的圖像集合。

這就是我必須為顯示成員列表的圖像網格小部件構建的內容。會員圖像來自 API,並隨著時間的推移而增長。

我決定用 Svelte 建造這個,因為為什麼不呢? !

更認真地說,我想要的東西將被編譯為所需的必要程式碼量,並且在網站上佔用的空間非常小。
基於此,我有兩個選擇:

  • 使用 vanilla javascript 建構它
  • 使用一個 javascript 函式庫,它將產生一個非常小的包,特別是考慮到該專案也非常小。

此外,我發現 svelte 模型更簡單、更直觀,因此如果有選擇,尤其是在像這樣的小項目上,我將預設使用它。

正如您進一步看到的那樣,與其他解決方案相比,svelte 使得處理許多小而複雜的狀態變化變得非常簡單(同樣,個人品味)。
通常,把事情搞砸的方法會更少。

核心組件

我們的實作由兩個主要的 Svelte 元件組成:

  1. App.svelte - 管理網格和協調影像交換的主要元件
  2. MemberImageCard.svelte - 處理翻轉動畫和圖像顯示的單獨卡片

狀態管理:網格背後的大腦

我們小部件的核心在於它的狀態管理。我們需要追蹤幾個訊息:

let allImages: Image[]; // All available images
let imagesToUse: Image[] = []; // Initial grid images
let imagesInUse: Image[] = []; // Current grid state
let remainingImages: Image[] = []; // Pool of unused images
let imagesSwapMap = new Map<number, Image>(); // Tracks pending swaps

為什麼要單獨追蹤當前狀態?

您可能想知道為什麼我們將 imagesInUse 與 imagesToUse 分開維護。這種分離有幾個重要目的:

  1. 它為目前網格狀態提供單一事實來源
  2. 它有助於防止重複的圖像出現在網格中
  3. 它可以實現高效更新,無需完全網格重新渲染
  4. 它在交換操作期間保持網格完整性

交換編排:詳細觀察

影像交換過程是一個精心策劃的序列,可確保平滑過渡,同時保持網格完整性。讓我們一步步分解 switchImages 函數:

let allImages: Image[]; // All available images
let imagesToUse: Image[] = []; // Initial grid images
let imagesInUse: Image[] = []; // Current grid state
let remainingImages: Image[] = []; // Pool of unused images
let imagesSwapMap = new Map<number, Image>(); // Tracks pending swaps

1. 從池中選擇影像

首先,我們需要確定剩餘池中的哪些影像將用於交換:

const switchImages = () => {
  let newImagesSwapMap = new Map<number, Image>()
  let remainingImagesToUse
  let newRemainingImages: Image[]

此程式碼處理兩種情況:

  • 如果剩餘影像不足,我們會使用所有影像
  • 否則,我們從池中取得最後 N 張影像,其中 N 是 NUMBER_OF_IMAGES_TO_SWITCH

2. 選擇網格位置

接下來,我們在網格中隨機選擇要交換影像的位置:

if (remainingImages.length <= NUMBER_OF_IMAGES_TO_SWITCH) {
 // If we have fewer remaining images than needed, use all of them
 remainingImagesToUse = remainingImages.slice(0);
 newRemainingImages = [];
} else {
 // Take the last N images from the remaining pool
 remainingImagesToUse = remainingImages.slice(-NUMBER_OF_IMAGES_TO_SWITCH);
 // Keep the rest for future swaps
 newRemainingImages = remainingImages.slice(0, -NUMBER_OF_IMAGES_TO_SWITCH);
}

這會在我們的網格大小內建立一個隨機索引陣列。例如,如果 NUMBER_OF_IMAGES_TO_SWITCH 為 1 且 NUMBER_OF_IMAGES_TO_USE 為 16,我們可能會得到 [7],表示我們將交換網格中位置 7 的圖像。

3. 防止重複

在執行任何交換之前,我們檢查新影像是否已顯示:

indexesToSwap = Array(NUMBER_OF_IMAGES_TO_SWITCH)
 .fill(null)
 .map(() => Math.floor(Math.random() * NUMBER_OF_IMAGES_TO_USE));

此功能可防止相同影像在我們的網格中多次出現。

4. 互換操作

現在是核心交換邏輯:

const imageIsInUse = (image: Image) => {
 const inUse = imagesInUse.find((img: Image) => image.picture_url === img.picture_url);
 return inUse;
};

讓我們分解一下每次交換中會發生什麼:

  1. 我們得到隨機選擇的位置(索引)
  2. 我們辨識該位置的目前影像(imageToSwap)
  3. 我們從池中取得新映像 (imageToSwapWith)
  4. 如果新圖像有效且尚未顯示:
    • 我們將交換記錄在imagesSwapMap中
    • 我們更新imagesInUse中的網格狀態
    • 我們在開始時將舊圖像添加回池中

5. 確定狀態

執行所有交換後,我們更新狀態:

for (let i = 0; i < indexesToSwap.length; i++) {
 let index = indexesToSwap[i];
 let imageToSwap = imagesInUse[index]; // Current image in the grid
 let imageToSwapWith = remainingImagesToUse.pop(); // New image to display

 if (imageToSwapWith && !imageIsInUse(imageToSwapWith)) {
  // Record the swap in our map
  newImagesSwapMap.set(index, imageToSwapWith);
  // Update the swap map to trigger component updates
  imagesSwapMap = newImagesSwapMap;
  // Update the grid state
  imagesInUse[index] = imageToSwapWith;
  // Add the old image back to the pool
  newRemainingImages.unshift(imageToSwap);
 } else {
  return; // Skip if the image is already in use
 }
}

6. 觸發動畫

imagesSwapMap是觸發動畫的關鍵。當它更新時,相關的 MemberImageCard 組件會做出反應:

remainingImages = newRemainingImages;
imagesInUse = imagesInUse;

MemberImageCard 中的此反應語句:

  1. 偵測其位置何時涉及交換
  2. 在卡片的反面載入新圖片
  3. 透過改變faceOnDisplay觸發翻轉動畫
  4. 重置影像載入狀態以實現平滑過渡

這個系統的美妙之處在於它保持流暢的使用者體驗,同時確保:

  • 網格中沒有出現重複的影像
  • 影像高效循環
  • 網格始終保持其結構
  • 動畫順利且可預測地發生
  • 失敗的交換(由於重複)會被妥善處理

翻轉動畫:使其平滑

每個 MemberImageCard 元件使用 CSS 變換和轉換來管理自己的翻轉動畫。神奇的事情是透過狀態追蹤和 CSS 的結合來實現的:

let allImages: Image[]; // All available images
let imagesToUse: Image[] = []; // Initial grid images
let imagesInUse: Image[] = []; // Current grid state
let remainingImages: Image[] = []; // Pool of unused images
let imagesSwapMap = new Map<number, Image>(); // Tracks pending swaps
const switchImages = () => {
  let newImagesSwapMap = new Map<number, Image>()
  let remainingImagesToUse
  let newRemainingImages: Image[]

當影像需要交換時,我們:

  1. 在反面載入新圖片
  2. 觸發翻轉動畫
  3. 翻轉完成後清理舊影像

漸進式載入以獲得更好的用戶體驗

為了增強使用者體驗,我們實現了漸進式載入效果:

if (remainingImages.length <= NUMBER_OF_IMAGES_TO_SWITCH) {
 // If we have fewer remaining images than needed, use all of them
 remainingImagesToUse = remainingImages.slice(0);
 newRemainingImages = [];
} else {
 // Take the last N images from the remaining pool
 remainingImagesToUse = remainingImages.slice(-NUMBER_OF_IMAGES_TO_SWITCH);
 // Keep the rest for future swaps
 newRemainingImages = remainingImages.slice(0, -NUMBER_OF_IMAGES_TO_SWITCH);
}

載入後影像開始模糊並平滑淡入,提供精美的外觀和感覺。

安排舞蹈

定期的影像交換是使用 Svelte 的 onMount 生命週期函數來安排:

indexesToSwap = Array(NUMBER_OF_IMAGES_TO_SWITCH)
 .fill(null)
 .map(() => Math.floor(Math.random() * NUMBER_OF_IMAGES_TO_USE));

結論

此實作展示了 Svelte 反應功能與現代 CSS 轉換相結合的強大功能,可建立動態、引人入勝的 UI 元件。

以上是使用 Svelte 建立動態影像網格:實現翻轉卡過渡的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn