Exemple de composant utilisant une animation

Cet exemple présente un composant utilisant une animation CSS et un effet créé avec la fonction createEffect().

Description du composant

Ce composant reprend les mêmes fonctionnalités que le composant utilisé comme exemple pour décrire la réactivité dans un composant. C’est donc un diaporama d’images mais avec une animation (fadeOut / fadeIn) au passage d’une image à une autre.

Le composant est une fonction AnimatedSlideShow attendant une propriété images et retournant un élément <div>.

La propriété images est requise et doit être un tableau à minima vide ([]). Les éléments du tableau sont des objets et un objet doit être constitué d’une propriété src contenant l’URL d’une image et d’une propriété title contenant un texte associé à l’image.

Un exemple de tableau :

const images = [
{
src: "https://picsum.photos/960/540?random=0",
title: "Image n° 1 provenant du site Lorem Picsum"
},
{
src: "https://picsum.photos/960/540?random=1",
title: "Image n° 2 provenant du site Lorem Picsum"
}
];

Code du composant

Le code du composant est représenté ici.

function AnimatedSlideShow({images}) {
const {div, figure, img, figcaption, button, p} = Room.elements();

const index = Room.createData(1);
const fadeIn = "fadeIn 250ms ease-in forwards";
const fadeOut = "fadeOut 250ms ease-out forwards";

const loaded = () => image.style.animation = fadeIn;
const title = () => images[index - 1].title;
const setImage = () => {
image.src = images[index - 1].src;
image.alt = title();
};

const image = img({onLoad: loaded, onError: loaded});

const updateImage = () => {
image.addEventListener("animationend", setImage, {once: true});
image.style.animation = fadeOut;
};

Room.createEffect(updateImage, index);

return div({class: "slideShow"},
Array.isArray(images) && images.length ? [
figure(
image,
figcaption(title)
),
div(
button("Précédent", {
onClick: () => index.value--,
disabled: () => index.value == 1
}),
p(index, " / ", images.length),
button("Suivant", {
onClick: () => index.value++,
disabled: () => index.value == images.length
})
)
] : ""
);
}

Ce code est identique à l’autre composant pour la partie structure du HTML retourné dans l’élément <div>. La différence importante est l’utilisation d’un effet créé avec la fonction createEffect() en utilisant la fonction updateImage() et une dépendance sur la donnée observable index.

Il est ici important de noter que l’effet est créé en forçant une dépendance sur la donnée observable index car la fonction updateImage() ne consulte jamais cette donnée, Room est donc incapable de capturer cette dépendance.

C’est la fonction updateImage() qui va réaliser le chargement d’une image, à la fois la première et les suivantes quand un clic se produit sur les boutons. Pour cela, elle met en place une animation CSS de type fadeOut sur l’image en cours et qui à la fin de l’animation, change l’image (les attributs src et alt de l’élément <img>) via la fonction setImage().

Cette fonction setImage() est le gestionnaire de l’évènement animationend qui est ajouté à l’image via la fonction addEventListener() et l’option once à true pour qu’il ne soit invoqué qu’une fois et supprimé après le traitement.

La fonction updateImage() a besoin d’avoir une référence à l’élément <img> pour réaliser son traitement, il est donc pré-construit dans une variable image donnant ainsi l’accès à toutes les fonctions qui en ont besoin, à l’élément <img> contenu dans l’élément <div> du composant.

Quand la nouvelle image est chargée (ou en cas d’erreur de chargement) un événement onload (ou onerror en cas d’erreur) est généré pour l’image et la fonction loaded(), qui a été attribuée à ces évènements à la pré-construction de l’élément <img>, est donc exécutée. Et c’est elle qui met en place l’animation fadeIn via la modification de l’attribut style de l’image.

Pour les animations, nous avons juste au niveau CSS les keyframes suivants :

@keyframes fadeOut {
from {opactity: 1}
to {opacity: 0.3}
}

@keyframes fadeIn {
from {opacity: 0.3}
to {opacity: 1}
}

Utilisation du composant

En supposant que nous avons un tableau d’images au format indiqué plus haut dans une variable images, alors ce composant peut être ajouté dans un élément avec une ligne de code.

element.append(AnimatedSlideShow({images}));

Ce qui donne le résultat suivant :

Dernière mise à jour :