Bonjour. Je convertis petit à petit mes outils fronts jQuey en vanilla js, et en ce moment c'est au tour de mon menu accordéon (cf. l'ancien menu accordéon en live, et son code jQuery)...
Tant que j'y suis je tente de me mettre au goût du jour en partant non plus d'une liste à remapper mais à partir d'éléments details/summary... que je dois remapper de toute façon car ces éléments se montrent récalcitrants aux animations (pour un tas de raisons que je passerais ici, j'ai fais mes tests ; voir aussi cet exemple issu de Stack Overflow, non merci...).
Donc on a ça au départ :
Et ça doit donner ça au final :
Alors j'ai fais une tentative et pas de soucis ça marche (un CodePen en l'état) :
Mais cette partie du code (et les lignes qui lui ressemblent) est difficilement modulable :
Car par la suite je voudrais ajouter plusieurs fonctionnalités (présentes dans mon ancien code) :
- pendre en compte l'état d'un onglet ouvert,
- fermer tous les éléments frères déjà ouvert lorsqu'un nouvel onglet s'ouvre
- donner un style particulier à un onglet,
- ...
Ce qui me demande de détecter/ajouter encore une ou plusieurs classes à tel ou tel de mes éléments. Je suis sûr qu'il y a une meilleure manière de procéder que ma méthode actuelle, mais comment ?
Modifié par Olivier C (17 Jun 2020 - 16:23)
Tant que j'y suis je tente de me mettre au goût du jour en partant non plus d'une liste à remapper mais à partir d'éléments details/summary... que je dois remapper de toute façon car ces éléments se montrent récalcitrants aux animations (pour un tas de raisons que je passerais ici, j'ai fais mes tests ; voir aussi cet exemple issu de Stack Overflow, non merci...).
Donc on a ça au départ :
<div class="accordion">
<details>
<summary>Item 1</summary>
<div>
<p>Lorem ipsum dolor...</p>
</div>
</details>
<details>
<summary>Item 2</summary>
<div>
<p>Lorem ipsum dolor...</p>
</div>
</details>
</div>
Et ça doit donner ça au final :
<div class="accordion">
<div class="accordion-details">
<button type="button" class="accordion-summary">Item 1</button>
<div class="accordion-content" style="">
<p>Lorem ipsum dolor...</p>
</div>
</div>
<div class="accordion-details">
<button type="button" class="accordion-summary">Item 2</button>
<div class="accordion-content" style="">
<p>Lorem ipsum dolor...</p>
</div>
</div>
</div>
Alors j'ai fais une tentative et pas de soucis ça marche (un CodePen en l'état) :
const accordion = (() => {
const detailss = document.querySelectorAll('.accordion details');
for (const details of detailss) {
let summary = details.firstElementChild,
content = details.lastElementChild;
summary.outerHTML = '<button type="button" class="accordion-summary">' + summary.innerHTML + '</button>';
content.outerHTML = '<div class="accordion-content">' + content.innerHTML + '</div>';
details.outerHTML = '<div class="accordion-details">' + details.innerHTML + '</div>'; // L'élément parent doit être traité en dernier.
}
const accordionSummarys = document.querySelectorAll('.accordion-summary');
for (const accordionSummary of accordionSummarys) accordionSummary.addEventListener('click', () => {
accordionSummary.parentElement.classList.toggle('open');
const accordionContent = accordionSummary.nextElementSibling;
const height = accordionContent.style.maxHeight === accordionContent.scrollHeight + 'px' ? null : accordionContent.scrollHeight + 'px';
accordionContent.style.maxHeight = height;
});
})();
Mais cette partie du code (et les lignes qui lui ressemblent) est difficilement modulable :
content.outerHTML = '<div class="accordion-content">' + content.innerHTML + '</div>';
Car par la suite je voudrais ajouter plusieurs fonctionnalités (présentes dans mon ancien code) :
- pendre en compte l'état d'un onglet ouvert,
- fermer tous les éléments frères déjà ouvert lorsqu'un nouvel onglet s'ouvre
- donner un style particulier à un onglet,
- ...
Ce qui me demande de détecter/ajouter encore une ou plusieurs classes à tel ou tel de mes éléments. Je suis sûr qu'il y a une meilleure manière de procéder que ma méthode actuelle, mais comment ?
Modifié par Olivier C (17 Jun 2020 - 16:23)