Accordion Refactor
Jetzt wird aufgeräumt, durchgeputzt … aus imperativem Code wird deklarativer, und wir schreiben single purpose Funktionen.
Unser Code sieht aktuell so aus:
const accordionContainer = document.querySelector('.accordion-container');
accordionContainer.addEventListener('click', e => { const accordionHeader = e.target.closest('.accordion-header'); if (!accordionHeader) return;
const accordion = accordionHeader.parentElement;
// we need this part to calculate the height: const accordionContent = accordionHeader.nextElementSibling; const accordionInner = accordionContent.children[0]; const height = accordion.classList.contains('is-open') ? 0 : accordionInner.getBoundingClientRect().height; ///
accordion.classList.toggle('is-open'); accordionContent.style.height = `${height}px`;})Get content height
Section titled “Get content height”Im ersten Schritt wollen wir eine Funktion zur Ermittlung der Höhe schreiben. Eine gute Bezeichnung ist function getContentHeight() – sie beschreibt den Zweck der Funktion genau. Wir packen alles, was zur Ermittlung der Höhe dazugehört, in diese Funktion:
function getContentHeight() { const accordionContent = accordionHeader.nextElementSibling; const accordionInner = accordionContent.children[0]; const height = accordion.classList.contains('is-open') ? 0 : accordionInner.getBoundingClientRect().height;}Wenn wir die Funktion getContentHeight() aufrufen, möchten wir, dass sie uns den Wert der Höhe zurückgibt – das ist der Zweck der Funktion. Wir fügen also ein return ein:
function getContentHeight() { // ... return accordion.classList.contains('is-open') ? 0 : accordionInner.getBoundingClientRect().height;}getContentHeight() benötigt zwei Variable: accordionHeader und accordion. accordionHeader benötigen wir, um accordionContent und accordionInner zu erhalten, und accordion wird benötigt, um zu prüfen, ob das Accordeon geöffnet ist. Wir könnten jetzt beide Variable als Argumente übergeben …
function getContentHeight(accordion, accordionHeader) { // ...}… aber bei genauer Betrachtung sehen wir, dass wir accordionHeader auch aus accordion direkt erhalten, ohne Umweg über accordionHeader und accordionContent:
function getContentHeight(accordion) { const accordionInner = accordion.querySelector('.accordion-inner');
return accordion.classList.contains('is-open') ? 0 : accordionInner.getBoundingClientRect().height;}In diesem Fall ist ein if Statement deutlich besser lesbar als ein ternary Operator:
function getContentHeight(accordion) { const accordionInner = accordion.querySelector('.accordion-inner');
if (accordion.classList.contains('is-open')) return 0; return accordionInner.getBoundingClientRect().height;}Zum Schluss wollen wir die Funktion noch kommentieren:
/** * Returns the height of the accordion content * @param {HTMLElement} accordion The accordion * @returns {Number} The accordion content's height in px */function getContentHeight(accordion) { // ...}Unser Code mit dem Aufruf der Funktion im EventListener sieht nun so aus:
const accordionContainer = document.querySelector('.accordion-container');
/** * Returns the height of the accordion content * @param {HTMLElement} accordion The accordion * @returns {Number} The accordion content's height in px */function getContentHeight(accordion) { const accordionInner = accordion.querySelector('.accordion-inner');
if (accordion.classList.contains('is-open')) return 0; return accordionInner.getBoundingClientRect().height;}
accordionContainer.addEventListener('click', e => { const accordionHeader = e.target.closest('.accordion-header'); if (!accordionHeader) return;
const accordion = accordionHeader.parentElement; // function call: const height = getContentHeight(accordion);
accordion.classList.toggle('is-open'); accordionContent.style.height = `${height}px`;})Update accordion
Section titled “Update accordion”Auch das eigentliche Update des Accordeon-Status können wir in eine Funktion auslagern: function updateAccordion().