Bonne journée, mes amis!
Dans cet article, je vais vous montrer comment animer l'élément de détails natif à l'aide de l' API Web Animations .
Commençons par le balisage.
L'élément "détails" doit contenir un élément "résumé". résumé est la partie visible du contenu lorsque l'accordéon est fermé.
Tous les autres éléments font partie du contenu interne de l'accordéon. Pour faciliter notre tâche, nous allons envelopper ce contenu dans un div avec la classe "content".
<details>
<summary>Summary of the accordion</summary>
<div class="content">
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit.
Modi unde, ex rem voluptates autem aliquid veniam quis temporibus repudiandae illo, nostrum, pariatur quae!
At animi modi dignissimos corrupti placeat voluptatum!
</p>
</div>
</details>
Classe d'accordéon
Nous avons besoin d'une classe Accordion pour pouvoir réutiliser notre code. Avec une telle classe, nous pouvons instancier n'importe quel nombre de détails sur la page.
class Accordion {
constructor() {}
// , summary
onClick() {}
// ,
shrink() {}
// ,
open() {}
// ,
expand() {}
// , shrink expand
onAnimationFinish() {}
}
constructeur ()
Le constructeur est utilisé pour stocker les données nécessaires à l'accordéon.
constructor(el) {
// details
this.el = el
// summary
this.summary = el.querySelector('summary')
// div "content"
this.content = el.querySelector('.content')
// ( )
this.animation = null
// ?
this.isClosing = false
// ?
this.isExpanding = false
// summary
this.summary.addEventListener('click', (e) => this.onClick(e))
}
sur clic ()
Dans la fonction "onClick", on vérifie si l'élément est en cours d'animation (fermeture ou expansion). Nous devons le faire pour le cas où l'utilisateur clique sur l'accordéon avant la fin de l'animation. Nous ne voulons pas que l'accordéon passe de complètement ouvert à complètement fermé.
L'élément "details" a un attribut "open" ajouté par le navigateur lorsque l'élément est ouvert. Nous pouvons obtenir la valeur de cet attribut via this.el.open.
onClick(e) {
//
e.preventDefault()
// details "overflow" "hidden"
this.el.style.overflow = 'hidden'
// ,
if (this.isClosing || !this.el.open) {
this.open()
// ,
} else if (this.isExpanding || this.el.open) {
this.shrink()
}
}
rétrécir ()
La fonction de réduction utilise la fonction WAAPI "animer". Vous pouvez en savoir plus sur cette fonctionnalité ici . WAAPI est très similaire à l'instruction CSS "keyframes" en ce sens que nous devons définir des images clés pour l'animation. Dans ce cas, nous n'avons besoin que de deux cadres de ce type: le premier est la hauteur actuelle de l'élément de détails (ouvert), le second est la hauteur des détails fermés (hauteur du résumé).
shrink() {
//
this.isClosing = true
//
const startHeight = `${this.el.offsetHeight}px`
// summary
const endHeight = `${this.summary.offsetHeight}px`
//
if (this.animation) {
//
this.animation.cancel()
}
// WAAPI
this.animation = this.el.animate({
//
height: [startHeight, endHeight]
}, {
// , (duration - )
duration: 400,
// (easing (animation-timing-function) - )
easing: 'ease-out'
})
// onAnimationFinish()
this.animation.onfinish = () => this.onAnimationFinish(false)
// , "isClosing" "false"
this.animation.oncancel = () => this.isClosing = false
}
ouvert ()
La fonction "open" est appelée lorsque nous voulons ouvrir l'accordéon. Cette fonction ne contrôle pas l'animation de l'accordéon. Tout d'abord, nous calculons la hauteur de l'élément "details" et y ajoutons les styles en ligne appropriés. Une fois que cela est fait, nous pouvons lui ajouter un attribut "open" afin de rendre le contenu visible, mais en même temps masqué en raison d'un débordement: caché et la hauteur fixe de l'élément. Ensuite, nous attendons l'image suivante pour appeler la fonction d'expansion et animer l'élément.
open() {
//
this.el.style.height = `${this.el.offsetHeight}px`
// details "open"
this.el.open = true
// "expand"
requestAnimationFrame(() => this.expand())
}
développer ()
La fonction d'expansion est similaire à la fonction de réduction, mais au lieu d'animer de la hauteur actuelle de l'élément à sa hauteur fermée, nous l'animerons de la hauteur de l'élément à sa hauteur totale. La hauteur totale est la hauteur récapitulative plus la hauteur du contenu interne.
expand() {
//
this.isExpanding = true
//
const startHeight = `${this.el.offsetHeight}px`
// ( summary + )
const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`
//
if (this.animation) {
//
this.animation.cancel()
}
// WAAPI
this.animation = this.el.animate({
height: [startHeight, endHeight]
}, {
duration: 400,
easing: 'ease-out'
})
this.animation.onfinish = () => this.onAnimationFinish(true)
this.animation.oncancel = () => this.isClosing = false
}
onAnimationFinish ()
Cette fonction est appelée à la fin des détails de l'animation d'ouverture et de fermeture. Il prend un paramètre - une valeur booléenne pour l'attribut "open", qui n'est plus traité par le navigateur (si vous vous en souvenez, nous avons annulé le comportement par défaut du navigateur dans la fonction "onClick").
onAnimationFinish(open) {
// "open"
this.el.open = open
// ,
this.animation = null
//
this.isClosing = false
this.isExpanding = false
// overflow
this.el.style.height = this.el.style.overflow = ''
}
Initialisation des accordéons
Fuh! Nous avons presque fini.
Il ne reste plus qu'à créer une instance de la classe Accordion pour chaque élément de détails de la page.
document.querySelectorAll('details').forEach(el => {
new Accordion(el)
})
Remarques
Afin de calculer correctement la hauteur d'un élément dans les états ouvert et fermé, le résumé et le contenu doivent avoir la même hauteur tout au long de l'animation.
N'ajoutez pas de blancs internes pour le résumé ouvert, car cela peut entraîner des sauts soudains. Il en va de même pour le contenu interne: il doit avoir une hauteur fixe et vous devez éviter de changer sa hauteur lors de l'ouverture des détails.
N'ajoutez pas non plus de blancs externes entre le résumé et le contenu, car ils ne seront pas pris en compte lors du calcul de la hauteur des images clés. Au lieu de cela, utilisez un remplissage sur votre contenu pour ajouter de l'espace.
Conclusion
C'est ainsi que, facilement et simplement, nous avons réussi à créer un accordéon en pur JavaScript.
J'espère que vous avez trouvé quelque chose d'intéressant pour vous-même. Merci de votre attention.