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 fonctionupdateImage()
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 :