Infinite Scroll mit HTMX erstellen
Das Laden von Inhalten während des Scrollens eliminiert Paginierungs-Klicks und schafft ein flüssigeres Browsing-Erlebnis. Die traditionelle Implementierung von Infinite Scroll erfordert jedoch die Verwaltung von Intersection Observers, das Tracking von Zuständen und erheblichen JavaScript-Code. HTMX bietet einen einfacheren Ansatz: servergesteuertes Infinite Scroll mittels HTML-Attributen.
Dieser Leitfaden behandelt das kanonische HTMX Infinite-Scroll-Pattern, erklärt, wann revealed gegenüber intersect zu verwenden ist, und zeigt, wie man eine progressiv verbesserte Implementierung erstellt, die auch ohne JavaScript funktioniert.
Wichtigste Erkenntnisse
- HTMX Infinite Scroll verwendet ein sich selbst perpetuierendes Loader-Element-Pattern, bei dem jede Server-Antwort den nächsten Loader enthält
- Verwenden Sie
revealedfür ganzseitiges Scrolling undintersect oncefür scrollbare Container mit Overflow - Bauen Sie auf Standard-Paginierungs-Links auf für progressive Enhancement, das ohne JavaScript funktioniert
- Der Server kontrolliert den gesamten Paginierungs-Zustand durch das Loader-Element in jeder Antwort
Wie servergesteuertes Infinite Scroll funktioniert
Das Kernpattern platziert HTMX-Attribute auf einem “Loader”-Element – typischerweise das letzte Element in Ihrer Liste. Wenn dieses Element sichtbar wird, fordert HTMX die nächste Seite von Ihrem Server an. Der Server gibt HTML zurück, das sowohl die neuen Elemente als auch ein neues Loader-Element enthält, das auf die nachfolgende Seite verweist.
Hier ist die grundlegende Struktur:
<div id="items">
<div class="item">First item</div>
<div class="item">Second item</div>
<!-- Last rendered item doubles as the loader -->
<div class="item"
hx-get="/items?page=2"
hx-trigger="revealed"
hx-swap="afterend">
Last item of page 1
</div>
</div>
Die Server-Antwort für Seite 2 enthält Elemente und einen neuen Loader:
<div class="item">First item of page 2</div>
<div class="item">Second item of page 2</div>
<div class="item"
hx-get="/items?page=3"
hx-trigger="revealed"
hx-swap="afterend">
Last item of page 2
</div>
Dieses sich selbst perpetuierende Pattern setzt sich fort, bis der Server Inhalte ohne Loader zurückgibt und damit das Ende der verfügbaren Daten signalisiert.
HTMX Intersect vs. Revealed: Den richtigen Trigger wählen
HTMX bietet zwei sichtbarkeitsbasierte Trigger, und die Auswahl des falschen führt zu häufigen Bugs.
Verwenden Sie revealed für ganzseitiges Scrolling, bei dem das Dokument selbst scrollt. Dieser Trigger wird ausgelöst, wenn ein Element in den Browser-Viewport eintritt.
Verwenden Sie intersect once, wenn Inhalte innerhalb eines scrollbaren Containers mit CSS wie overflow-y: scroll liegen. Der revealed-Trigger überwacht den Dokument-Viewport, nicht einzelne scrollbare Elemente, sodass er in Overflow-Containern nicht korrekt ausgelöst wird. Der intersect-Trigger basiert auf der modernen Intersection Observer API, die in allen gängigen Browsern unterstützt wird.
<!-- Full-page scroll: use revealed -->
<div hx-trigger="revealed" hx-get="/more">...</div>
<!-- Scrollable container: use intersect once -->
<div class="scroll-container" style="overflow-y: scroll; height: 400px;">
<div hx-trigger="intersect once" hx-get="/more">...</div>
</div>
Der once-Modifier verhindert doppelte Anfragen, wenn das Element wiederholt die Intersection-Schwelle überschreitet.
Swap-Strategien: afterend vs. beforeend
Ihre Swap-Strategie bestimmt, wo neue Inhalte erscheinen und wie doppelte Ladevorgänge verhindert werden.
afterend fügt Inhalte unmittelbar nach dem Loader-Element ein. Verwenden Sie dies, wenn der Loader das zuletzt gerenderte Element ist – die Antwort erscheint darunter.
beforeend hängt Inhalte innerhalb eines Ziel-Containers an. Kombinieren Sie dies mit hx-target, um anzugeben, wohin die Elemente gehen:
<div hx-get="/items?page=2"
hx-trigger="revealed"
hx-target="#items"
hx-swap="beforeend">
Loading indicator...
</div>
Bei beforeend befindet sich Ihr Loader typischerweise außerhalb des Item-Containers und wird ersetzt oder entfernt, nachdem die letzte Seite geladen wurde.
Discover how at OpenReplay.com.
Progressive Enhancement mit Standard-Paginierung
Infinite Scrolling mit HTMX sollte auf bestehender Paginierung aufbauen, nicht diese vollständig ersetzen. Beginnen Sie mit funktionierenden Paginierungs-Links:
<div id="items">
{% for item in items %}
<div class="item">{{ item.name }}</div>
{% endfor %}
</div>
<a href="/items?page={{ next_page }}">Load more</a>
Dann erweitern Sie den Paginierungs-Link mit HTMX-Attributen:
<a href="/items?page={{ next_page }}"
hx-get="/items?page={{ next_page }}"
hx-trigger="revealed"
hx-target="#items"
hx-swap="beforeend"
hx-select="#items > *">
Load more
</a>
Benutzer ohne JavaScript sehen Standard-Paginierung. Benutzer mit HTMX erhalten Infinite Scroll. Der Server-Endpoint bleibt für beide identisch.
UI-Elemente mit Out-of-Band Swaps aktualisieren
Manchmal müssen Sie Elemente außerhalb des Hauptinhaltsbereichs aktualisieren – wie Element-Zähler oder Ladezustände. HTMX Out-of-Band Swaps handhaben dies:
<!-- In server response -->
<div class="item">New item</div>
<span id="item-count" hx-swap-oob="outerHTML">Showing 20 of 100</span>
Das Attribut hx-swap-oob="outerHTML" weist HTMX an, das Element mit übereinstimmender ID überall auf der Seite zu finden und zu ersetzen, unabhängig vom Haupt-Swap-Ziel.
Serverseitige Paginierungs-Strategien
Ihr Server kontrolliert den Paginierungs-Zustand vollständig. Zwei gängige Ansätze:
Offset-Paginierung verwendet Seitenzahlen oder Offset-Werte: /items?page=3 oder /items?offset=20. Einfach zu implementieren, kann aber Duplikate anzeigen, wenn während des Browsens Elemente hinzugefügt werden.
Cursor-Paginierung verwendet einen Zeiger auf das zuletzt gesehene Element: /items?after=item_xyz. Zuverlässiger für dynamische Inhalte, erfordert aber stabile Identifikatoren.
Beide Ansätze funktionieren mit HTMX – der Client übergibt einfach den Parameter, den der Server im nächsten Loader-Element bereitstellt.
Fazit
HTMX Infinite Scroll verlagert die Komplexität auf den Server, wo die Paginierungs-Logik bereits existiert. Wählen Sie revealed für Dokument-Scrolling und intersect once für Overflow-Container. Bauen Sie auf Standard-Paginierung auf, damit Ihr Feature elegant degradiert. Lassen Sie den Server den Zustand durch das Loader-Element jeder Antwort steuern, anstatt Seiten clientseitig zu tracken.
FAQs
Dies geschieht normalerweise, wenn intersect ohne den once-Modifier verwendet wird. Das Element kann wiederholt die Intersection-Schwelle überschreiten, während Inhalte geladen werden und das Layout sich verschiebt. Fügen Sie once zu Ihrem Trigger hinzu, wie hx-trigger intersect once, um sicherzustellen, dass nur eine einzige Anfrage pro Loader-Element ausgelöst wird.
Fügen Sie ein hx-indicator-Attribut hinzu, das auf Ihr Ladeelement verweist. Zum Beispiel hx-indicator mit einem Wert von hash loading auf Ihrem Loader-Element und einem separaten span mit id loading, das Ihren Spinner enthält. HTMX zeigt dieses Element automatisch während Anfragen an und verbirgt es, wenn diese abgeschlossen sind.
HTMX hilft, überlappende Anfragen zu verhindern, und jedes Loader-Element ist typischerweise so konfiguriert, dass es nur einmal ausgelöst wird. Die Server-Antwort bestimmt die nächste Seite. Wenn Sie eine strengere Koordination benötigen, können Sie hx-sync verwenden, um das Anfrageverhalten zu steuern.
Ja. Wenn sich Filter ändern, setzen Sie Ihren Content-Container zurück und aktualisieren Sie die Loader-URL, um Filterparameter einzuschließen. Der Server verarbeitet die Filterlogik und gibt die entsprechende erste Seite zurück. Jeder nachfolgende Loader enthält dieselben Filterparameter, um Konsistenz über Seiten hinweg zu gewährleisten.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.