jQuery / Plugin / jquery.toc — Überschriften als Inhaltsverzeichnis mit sanftem Scrollen

jquery.toc sammelt h1–h6 in einem gewählten Bereich und erzeugt verlinkte Einträge. .toc({ container: "#contents" }) am Artikel fügt das Verzeichnis an einem anderen Ort ein; Klicks scrollen zum Ziel. Trennen Sie Quelle und Verzeichnis und bestimmen Sie Überschriftenstruktur und Wiederaufbau.

Quelle und Dokument vorbereiten

Gemeint ist jquery.toc von jakobbossek. Mischen Sie Optionen nicht mit ähnlich benannten Plugins. Die geprüfte v1.1-Quelle ist auf einen Commit festgelegt. Speichern Sie die rohe Datei jquery.toc.js unter diesem Namen neben dem HTML, nicht die GitHub-Ansichtsseite.

Lokal liegen toc-demo.html und jquery.toc.js. Vollständiges jQuery 4.0.0 kommt vom CDN. Reihenfolge: jQuery, Plugin, Initialisierung. Slim fehlen benötigte Effekte. Die Quelle wurde mit 4.0.0 und 3.7.1 unter Windows Edge getestet.

Alle :header im gewählten Bereich werden gesammelt. #article begrenzt die Quelle; Verzeichnis, Dokumenttitel und aside liegen außerhalb. Zwei h3 folgen unter einem h2. Überspringen Sie Ebenen nicht zum Gestalten. Eine Option für maximale Tiefe implementiert diese Quelle nicht.

Vollständiges Beispiel mit Fokus und Wiederaufbau

Speichern und öffnen Sie UTF-8 als toc-demo.html. Kein Server oder Build ist nötig, Internet lädt jQuery. Die Überschriften sind kontrollierter einfacher Text. Das Plugin schreibt Überschriften-HTML neu und setzt Text in HTML-Zeichenketten ein; beliebige Eingaben und interaktive Links oder Schaltflächen in Überschriften sind nicht der Anwendungsbereich dieses Beispiels.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Generate a scoped table of contents</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script src="jquery.toc.js"></script>
  <style>
    html { scroll-behavior: auto; }
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
    #contents { border: 1px solid teal; padding: 16px; }
    #contents ul { padding-left: 24px; }
    #contents a { overflow-wrap: anywhere; }
    #article p { min-height: 440px; }
    h2:focus, h3:focus { outline: 3px solid teal; }
    button { font: inherit; }
    footer { min-height: 100vh; }
  </style>
</head>
<body>
  <h1>A focused table of contents</h1>
  <nav id="contents" aria-label="Article contents"><p>Contents will be generated when scripts load.</p></nav>
  <button type="button" id="rebuild">Rebuild original example</button>
  <p id="status" role="status">Article text is available below.</p>
  <main id="article">
    <h2 id="existing-overview">Overview</h2><p>First main topic with an existing stable ID.</p>
    <h3>Preparation</h3><p>First subtopic.</p>
    <h3>Verification</h3><p>Second subtopic.</p>
    <h2>Overview</h2><p>A different section with the same displayed title.</p>
  </main>
  <aside><h2>Outside the article</h2><p>This heading must not enter the contents.</p></aside>
  <footer>Space for the final destination.</footer>
  <script>
    jQuery(function ($) {
      if (typeof $.fn.toc !== "function") return;
      const $article = $("#article"), $toc = $("#contents"), original = $article.html();
      const $scroller = $(document.scrollingElement);
      let generation = 0;
      function build() {
        generation++; $scroller.stop(true, false);
        $article.html(original); $toc.empty().off("click.demo");
        $article.toc({ container: "#contents", strip: false, stripAfter: 30, scrollSpeed: 400, scrollOffset: 20 });
        // Replace this example's generated links' click handlers only.
        $toc.find("a").off("click");
        $toc.on("click.demo", "a[href^='#hl_']", function (event) {
          const anchor = document.getElementById(this.hash.slice(1));
          if (!anchor) return;
          event.preventDefault();
          const run = ++generation, heading = anchor.parentElement;
          $scroller.stop(true, false);
          const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
          $scroller.animate({ scrollTop: Math.max(0, $(heading).offset().top - 20) }, reduce ? 0 : 400, function () {
            if (run !== generation) return;
            heading.tabIndex = -1; heading.focus({ preventScroll: true });
            $("#status").text("Arrived: " + heading.textContent);
          });
        });
        $("#status").text("Entries: " + $toc.find("a").length);
      }
      $("#rebuild").on("click", function () { build(); window.scrollTo(0, 0); });
      build();
    });
  </script>
</body>
</html>

Anfangsergebnis; die zwei Overview-Texte bezeichnen verschiedene Abschnitte.

Entries: 4
  1. Prüfen Sie vier Einträge, davon die mittleren zwei verschachtelt. Outside the article fehlt.
  2. Der letzte Overview führt in 400ms zum Titel mit 20px Abstand und Fokusrahmen.
  3. Fokussieren Sie den Eintrag per Tastatur und drücken Sie Enter.
  4. Bei reduzierter Bewegung reduce erfolgt die Ankunft sofort.
  5. Rebuild original example stellt Anfang und Entries: 4 wieder her, auch mehrfach, ohne doppelte Listen oder verschachtelte Anker.
  6. Wiederaufbau während Bewegung darf keinen alten Abschlussstatus nachtragen.

Nach Erzeugung ersetzt die Übung nur die ursprünglichen Klickhandler ihrer Verzeichnislinks. Der Zusatz animiert ein tatsächliches Scrollelement und ergänzt Warteschlangenbereinigung, Abbrucherkennung, Fokus und reduzierte Bewegung. Die Originaldatei bleibt unverändert. URL-Fragment und Verlauf werden nicht geändert.

Grundaufruf und tatsächliche Optionen

Für das Originalverhalten behalten Sie die script-Tags der Initialisierung und ersetzen Sie deren gesamten Inhalt durch Folgendes. Dateien, Artikel und #contents bleiben; Wiederaufbauknopf und Status entfallen. Der Grundaufruf verwendet die Plugin-Animation ohne zusätzliche Fokus-, Bewegungs- oder Wiederaufbaulogik.

$("#article").toc({
  container: "#contents",
  strip: false,
  stripAfter: 30,
  scrollSpeed: 400,
  scrollOffset: 20
});

#article bestimmt die Quelle, container den Einfügeort. wrapWith bestimmt das umgebende HTML mit Standardklasse toc_container. Begrenzen Sie CSS auf #contents.

scrollSpeed ist Millisekundenzeit. Vergleichen Sie im Grundaufruf 400 mit 800 am selben Link und stellen Sie zurück. scrollOffset wird von der Koordinate des inneren Ankers abgezogen, positiv 20 lässt oben Platz. Der ergänzte Vollcode richtet dagegen die Überschriftenbox selbst auf 20px aus, was einige Pixel vom Inline-Anker abweichen kann.

Im Vollbeispiel ändern alleinige .toc()-Scrolloptionen den Ersatzhandler nicht. Ändern Sie dort animate-Zeit 400 oder den abgezogenen Wert 20; die Null für reduzierte Bewegung bleibt.

Die tatsächliche Kürzungsbedingung prüft strip. Trotz shorten in den Vorgaben aktiviert shorten:true diesen Zweig nicht. strip:true verwendet substring bis stripAfter und hängt jedem Eintrag ... an, auch kurzen. Es zählt Zeichenketteneinheiten statt Wörter und kann zusammengesetzte Zeichen wie Emoji teilen. Bevorzugen Sie für lesbare vollständige Texte strip:false.

Anker, vorhandene IDs und Integrationsgrenzen

Die Quelle überschreibt vorhandene Überschriften-IDs nicht, sondern setzt innen ein a mit etwa hl_112 ein. existing-overview bleibt bestehen. Generierte IDs entstehen aus Bereich, Reihenfolge und Ebene, nicht aus dem Text; die gleichnamigen Ziele sind hier verschieden. Unicode wird ebenfalls gesammelt, doch Umordnung kann IDs ändern. Verwenden Sie sie nicht als stabile Permalinkregel.

Das Original hängt Listen an und umschließt HTML bei Wiederholung erneut. Der Vollcode stellt den ursprünglichen HTML-Schnappschuss her und leert das Verzeichnis. Später ergänzter Inhalt, Eingabestatus oder direkte Eventbindungen bleiben dabei nicht erhalten. Ein Editor braucht eigene Verwaltung von aktuellem Inhalt und stabilen IDs.

Initialisieren Sie es nicht zusätzlich zu einem Theme oder WordPress-Shortcode für denselben Artikel. Das Übungsbeispiel ist vom Verzeichnissystem dieser Website getrennt. Die ursprüngliche Klickauswahl reicht global auf .toc-Listen; unabhängige Mehrfachinstanzen sind daher nicht selbstverständlich.

Fehlt das Verzeichnis, prüfen Sie Pfad und JavaScript-Inhalt der lokalen Datei, Reihenfolge, Überschriften und Ziel. Bei Versatz prüfen Sie fixierte Menüs, nachladende Bilder/Schriften und Platz am Ende. Lange Einträge können per CSS umbrechen; der Artikel muss auch ohne Verzeichnis lesbar bleiben.