Maison >interface Web >js tutoriel >Construire une grille d'images dynamique avec Svelte : implémenter des transitions de cartes à retourner

Construire une grille d'images dynamique avec Svelte : implémenter des transitions de cartes à retourner

Barbara Streisand
Barbara Streisandoriginal
2024-11-25 05:20:17165parcourir

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

La création d'interfaces utilisateur attrayantes nécessite souvent un équilibre délicat entre fonctionnalité et attrait visuel. Dans cet article, nous explorerons comment créer un composant de grille d'images dynamique à l'aide de Svelte qui non seulement gère efficacement l'état, mais fournit également des transitions fluides et accrocheuses lorsque les images entrent et sortent.

La vision

Imaginez une grille d'images qui se rafraîchit périodiquement, avec des cartes individuelles se retournant en douceur pour révéler de nouvelles images.

Cela crée un affichage attrayant, parfait pour présenter les membres de l'équipe, les catalogues de produits ou toute collection d'images plus grande que ce qui peut être affiché simultanément.

C'est ce que j'ai dû créer pour un widget de grille d'images présentant une liste de membres. Les images des membres proviennent d'une API et s'agrandissent avec le temps.

J'ai décidé de construire ça avec Svelte parce que, pourquoi pas ?!

Plus sérieusement, je voulais quelque chose qui serait compilé avec juste la quantité de code nécessaire et qui aurait une très petite empreinte sur le site Web.
Sur cette base, j'avais deux options :

  • Construisez-le avec du javascript vanilla
  • Utilisez une bibliothèque javascript qui va produire un très petit bundle, d'autant plus que le projet est également très petit.

De plus, je trouve le modèle svelte plus simple et plus intuitif donc étant donné le choix, surtout sur un petit projet comme celui-ci, c'est ce que je choisirai par défaut.

Comme vous le verrez un peu plus loin, svelte rend la gestion de nombreux changements d'état petits et complexes très simple par rapport à d'autres solutions (encore une fois, goût personnel).
Il y a généralement moins de façons de gâcher les choses.

Composants de base

Notre implémentation se compose de deux composants Svelte principaux :

  1. App.svelte - Le composant principal qui gère la grille et orchestre l'échange d'images
  2. MemberImageCard.svelte - Cartes individuelles qui gèrent l'animation flip et l'affichage des images

Gestion de l'État : le cerveau derrière la grille

Le cœur de notre widget réside dans sa gestion d'état. Nous devons suivre plusieurs informations :

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

Pourquoi suivre l’état actuel séparément ?

Vous vous demandez peut-être pourquoi nous maintenons imagesInUse séparément de imagesToUse. Cette séparation répond à plusieurs objectifs cruciaux :

  1. Il fournit une source unique de vérité sur l'état actuel du réseau
  2. Cela permet d'éviter que des images en double n'apparaissent dans la grille
  3. Il permet des mises à jour efficaces sans restituer la grille complète
  4. Il maintient l'intégrité du réseau pendant les opérations d'échange

La chorégraphie Swap : un aperçu détaillé

Le processus d'échange d'images est une séquence soigneusement orchestrée qui garantit des transitions fluides tout en maintenant l'intégrité de la grille. Décomposons la fonction switchImages étape par étape :

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. Sélection d'images dans le pool

Tout d'abord, nous devons déterminer quelles images de notre pool restant seront utilisées pour l'échange :

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

Ce code gère deux scénarios :

  • Si nous manquons d'images restantes, nous les utilisons toutes
  • Sinon, nous prenons les N dernières images de notre pool, où N est NUMBER_OF_IMAGES_TO_SWITCH

2. Choisir les positions sur la grille

Ensuite, nous sélectionnons au hasard les positions dans la grille où nous échangerons les images :

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);
}

Cela crée un tableau d'index aléatoires dans la taille de notre grille. Par exemple, si NUMBER_OF_IMAGES_TO_SWITCH vaut 1 et NUMBER_OF_IMAGES_TO_USE vaut 16, nous pourrions obtenir [7], indiquant que nous échangerons l'image à la position 7 dans la grille.

3. Prévenir les doublons

Avant d'effectuer tout échange, nous vérifions si la nouvelle image est déjà affichée :

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

Cette fonction évite qu'une même image apparaisse plusieurs fois dans notre grille.

4. L'opération d'échange

Vient maintenant la logique d'échange de base :

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

Décomposons ce qui se passe dans chaque échange :

  1. Nous obtenons la position sélectionnée au hasard (index)
  2. Nous identifions l'image actuelle à cette position (imageToSwap)
  3. Nous prenons une nouvelle image de notre pool (imageToSwapWith)
  4. Si la nouvelle image est valide et n'est pas déjà affichée :
    • Nous enregistrons l'échange dans imagesSwapMap
    • Nous mettons à jour l'état de la grille dans imagesInUse
    • Nous ajoutons l'ancienne image à la piscine au début

5. Finalisation de l'État

Après avoir effectué tous les échanges, nous mettons à jour notre état :

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. Déclenchement de l'animation

Les imagesSwapMap sont la clé pour déclencher des animations. Lors de sa mise à jour, les composants MemberImageCard concernés réagissent :

remainingImages = newRemainingImages;
imagesInUse = imagesInUse;

Cette déclaration réactive dans MemberImageCard :

  1. Détecte quand sa position est impliquée dans un swap
  2. Charge la nouvelle image sur le recto opposé de la carte
  3. Déclenche l'animation flip en changeant faceOnDisplay
  4. Réinitialise les états de chargement des images pour des transitions fluides

La beauté de ce système est qu'il maintient une expérience utilisateur fluide tout en garantissant :

  • Aucune image en double n'apparaît dans la grille
  • Les images défilent efficacement
  • La grille conserve toujours sa structure
  • Les animations se déroulent de manière fluide et prévisible
  • Les échanges ayant échoué (en raison de doublons) sont traités avec élégance

L'animation Flip : la rendre fluide

Chaque composant MemberImageCard gère sa propre animation flip à l'aide de transformations et de transitions CSS. La magie opère grâce à une combinaison de suivi d'état et de 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[]

Lorsqu'une image doit être échangée, nous :

  1. Chargez la nouvelle image au verso
  2. Déclenchez l'animation de retournement
  3. Nettoyez l'ancienne image une fois le retournement terminé

Chargement progressif pour une meilleure UX

Pour améliorer l'expérience utilisateur, nous avons mis en place un effet de chargement progressif :

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);
}

Les images commencent à être floues et s'estompent doucement une fois chargées, offrant ainsi une apparence et une sensation soignées.

Programmer la danse

Les échanges d'images réguliers sont planifiés à l'aide de la fonction de cycle de vie onMount de Svelte :

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

Conclusion

Cette implémentation met en valeur la puissance des capacités réactives de Svelte combinées aux transformations CSS modernes pour créer un composant d'interface utilisateur dynamique et attrayant.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn