Skip to content

Tabby – refactoring

Wir haben nun zwei Events für Tabby: eines lauscht auf einen Mausklick, eines auf die Pfeiltasten. Das lässt sich vereinfachen.

Den Großteil des Codes für das Click-Event können wir in eine Funktion selectTab() auslagern:

/**
* Selects a tab and the corresponding tab-content
* @param {HTML-Element} tab | Tab that was clicked
* @returns {}
*/
function selectTab() {
const tab = e.target;
const target = tab.dataset.target;
const tabContent = tabby.querySelector('#' + target);
// Selects a tab
tabs.forEach(t => {
t.classList.remove('is-selected');
t.setAttribute('tabindex', '-1');
});
tab.classList.add('is-selected');
tab.removeAttribute('tabindex');
// Selects the corresponding tab content
tabsContents.forEach(c => c.classList.remove('is-selected'));
tabContent.classList.add('is-selected');
}

Folgende Variable brauchen wir:

  • tab
  • tabs
  • tabContent
  • tabsContents

Wir erhalten diese aus:

  • tab aus e.target
  • tabs aus dem global scope
  • tabContent aus tab (bzw. daraus abgeleitet target)
  • tabsContentsaus dem global scope

Das bedeutet, dass wir der Funktion nur tab als Argument übergeben müssen:

function selectTab(tab) {
const target = tab.dataset.target;
const tabContent = tabby.querySelector('#' + target);
// ...
}

Verwendung von selectTab() im EventListener:

tabsList.addEventListener('click', e => {
const tab = e.target;
selectTab(tab);
});

In den ersten zwei Zeilen des EventListeners für das Keydown-Event entscheiden wir nur, ob wir auf den Event reagieren oder nicht. Dieser Teil kann nicht woanders hingeschoben werden.
In der dritten Zeile prüfen wir, welches Tab aktuell ausgewählt wurde bzw. im Fokus ist. Auch diese Zeile muss hier bleiben.

tabsList.addEventListener('keydown', e => {
const { key } = e;
if (key !== 'ArrowLeft' || key !== 'ArrowRight') return;
const index = tabs.findIndex(t => t.classList.contains('is-selected'));
// ...
});

Die nächsten Zeilen werden dazu verwendet, den Zieltab zu finden, also:

  • entscheiden, ob wir den vorhergehenden oder den nächsten Tab haben wollen
  • den vorhergehenden oder den nächsten Tab finden
  • ein Click-Event triggern

Um den Code zu vereinfachen, können wir zwei Funktionen getPreviousTab und getNextTab schreiben:

function getPreviousTab() {
if (key === 'ArrowLeft' && index !== 0) targetTab = tabs[index - 1];
}
function getNextTab() {
if (key === 'ArrowRight' && index !== tabs.length - 1) targetTab = tabs[index + 1];
}

Welche Taste gedrückt wurde, ist innerhalb dieser Funktion eigentlich nicht relevant, daher können wir diesen Teil aus den Funktionen rausnehmen:

function getPreviousTab() {
if (index !== 0) targetTab = tabs[index - 1];
}
function getNextTab() {
if (index !== tabs.length - 1) targetTab = tabs[index + 1];
}

Wir müssen aber den vorhergehden bzw. den nächsten Tab in der Funktion als Rückgabewert definieren:

function getPreviousTab() {
if (index !== 0) {
return tabs[index - 1];
}
}
function getNextTab() {
if (index !== tabs.length - 1) {
return tabs[index + 1];
}
}

Wir brauchen zwei Variable für die beiden Funktionen:

  • tabs
  • index

tabs bekommen wir aus dem global scope, daher müssen wir nur index als Argument mitgeben:

/**
* Selects the previous tab
* @param {number} index | Index of the selected tab
* @returns {number} index of the previous tab
*/
function getPreviousTab(index) {
if (index !== 0) {
return tabs[index - 1];
}
}
/**
* Selects the next tab
* @param {number} index | Index of the selected tab
* @returns {number} index of the next tab
*/
function getNextTab(index) {
if (index !== tabs.length - 1) {
return tabs[index + 1];
}
}

Verwendung von previousTab() und nextTab():

document.addEventListener('keydown', e => {
// ...
const index = tabs.findIndex(t => t.classList.contains('is-selected'));
let targetTab;
if (key === 'ArrowLeft') targetTab = getPreviousTab(index);
if (key === 'ArrowRight') targetTab = getNextTab(index);
// ...
})

Das macht mehr Sinn:

  1. Wenn Pfeil-nach-links-Taste, nehmen wir den vorhergehenden Tab
  2. Wenn Pfeil-nach-rechts-Taste, nehmen wir den nächsten Tab

Eine letzte Verbesserung geht auch noch: Wenn wir den targetTab gefunden haben, haben wir einen Klick drauf getriggert.

document.addEventListener('keydown', e => {
// ...
if (targetTab) {
targetTab.click();
}
});

Wenn wir diesen Code lesen, verstehen wir, dass wir ein click Event getriggert haben, das den passenden Tab mit selectTab() auswählt.