1unitedpower: Tabellenspalte bei :hover markieren

Beitrag lesen

das sind doch mal zwei (Felix' und deiner) gute Vorschläge. Welchen übernehmen wir für das Wiki?

Mir gefällt an Felix' Lösung besser, dass sie ohne Event-Delagation arbeitet. Mouse-Events können sehr häufig auftreten, da dürfte es etwas sparsamer sein, wenn die Event-Handler direkt an den Zellen registriert werden und nicht am document. Event-Delegation hat dafür den Vorteil, dass sie auch funktioniert, wenn eine Zelle dynamisch nachgeladen wird. Ich weiß nicht, ob es diesen Fall im Wiki gibt.

Außerdem halte ich es für robuster mit cellIndex anstatt mit nth-child zu arbeiten. Dann funktioniert das auch mit colSpan.

Ansonsten sind mir noch ein paar Kleinigkeiten aufgefallen, deshalb habe ich Felix' Version nochmal etwas überarbeitet. Ich habe zwei Versionen daraus gemacht, jenachdem ob der IE11 noch unterstüzt werden soll oder nicht. FF, Chrome und Edge habe ich jeweils in der aktuellen Version getestet. Zu Safari habe ich momentan keinen Zugang.

Nur für FF, Chrome und Edge:

window.addEventListener('DOMContentLoaded', _ => {
  const cells = document.querySelectorAll(
    'table.highlightable-columns td:not([colspan]), table.highlightable-columns th:not([colspan])'
  )
  for (const cell of cells) {
    cell.addEventListener('mouseenter', toggleColumn)
    cell.addEventListener('mouseleave', toggleColumn)
  }

  function toggleColumn (event) {
    const target = event.target
    const table = target.closest('table') || {rows: []}
    for (const row of table.rows) {
      for (const cell of row.cells) {
        const show = event.type === 'mouseenter'
          && cell.cellIndex === target.cellIndex
          && cell.colSpan === 1
        cell.classList.toggle('highlight', show)
      }
    }
  }
})

Die IE11-taugliche Version folgt dem selben Schema wie oben, aber mit extra Funktionen, die nicht nativ unterstützt werden.

window.addEventListener('DOMContentLoaded', function () {
  const cells = document.querySelectorAll(
    'table.highlightable-columns td:not([colspan]), table.highlightable-columns th:not([colspan])'
  )
  forEach(function (cell) {
    cell.addEventListener('mouseenter', toggleColumn)
    cell.addEventListener('mouseleave', toggleColumn)
  }, cells)

  function toggleColumn (event) {
    const target = event.target
    const table = closest('table', target)
    if (table instanceof HTMLTableElement) {
      const cells = table.querySelectorAll('td, th')
      forEach(function (cell) {
        const show = event.type === 'mouseenter'
          && cell.cellIndex === target.cellIndex
          && cell.colSpan === 1
        toggle('highlight', show, cell.classList)
      }, cells)
    }
  }

  function forEach(f, collection) {
    return Array.prototype.forEach.call(collection, f)
  }

  function closest (selector, target) {
    do {
      if (matches(selector, target)) {
        return target
      }
      target = target.parentElement
    } while (target !== null)
    return null
  }

  function matches (selector, target) {
    if (target.matches instanceof Function) {
      return target.matches(selector)
    } else if (target.msMatchesSelector instanceof Function) {
      return target.msMatchesSelector(selector)
    }
  }

  function toggle (className, state, classList) {
    if (state) {
      classList.add(className)
    } else {
      classList.remove(className)
    }
  }
})

Und sollte eine Alternative Bedienmöglichkeit für Touch-Geräte angeboten werden?