Scroll-Wiederherstellung

Hash/Seitenanfang-Scrolling

Out of the box unterstützt TanStack Router sowohl Hash-Scrolling als auch Seitenanfang-Scrolling ohne zusätzliche Konfiguration.

Scroll-to-top & Verschachtelte scrollbare Bereiche

Standardmäßig ahmt Scroll-to-top das Verhalten des Browsers nach, was bedeutet, dass nach erfolgreicher Navigation nur das window selbst nach oben gescrollt wird. Für viele Apps ist es jedoch üblich, dass der Haupt-Scrollbereich aufgrund fortgeschrittener Layouts ein verschachteltes Div oder ähnliches ist. Wenn Sie möchten, dass TanStack Router auch diese Haupt-Scrollbereiche für Sie scrollt, können Sie Selektoren hinzufügen, um sie mit routerOptions.scrollToTopSelectors anzusprechen.

tsx
const router = createRouter({
  scrollToTopSelectors: ['#main-scrollable-area'],
})
const router = createRouter({
  scrollToTopSelectors: ['#main-scrollable-area'],
})

Für komplexe Selektoren, die nicht einfach mit document.querySelector(selector) aufgelöst werden können, können Sie Funktionen übergeben, die HTML-Elemente zurückgeben, an routerOptions.scrollToTopSelectors.

tsx
const selector = () =>
  document
    .querySelector('#shadowRootParent')
    ?.shadowRoot?.querySelector('#main-scrollable-area')

const router = createRouter({
  scrollToTopSelectors: [selector],
})
const selector = () =>
  document
    .querySelector('#shadowRootParent')
    ?.shadowRoot?.querySelector('#main-scrollable-area')

const router = createRouter({
  scrollToTopSelectors: [selector],
})

Diese Selektoren werden zusätzlich zu window behandelt, was derzeit nicht deaktiviert werden kann.

Scroll-Wiederherstellung

Scroll-Restoration ist der Prozess, die Scroll-Position einer Seite wiederherzustellen, wenn der Benutzer zu ihr zurückkehrt. Dies ist normalerweise eine integrierte Funktion für Standard-HTML-basierte Websites, kann aber für SPA-Anwendungen schwierig zu replizieren sein, weil

  • SPAs verwenden typischerweise die history.pushState API für die Navigation, sodass der Browser die Scroll-Position nicht nativ wiederherstellen kann.
  • SPAs rendern manchmal Inhalte asynchron, sodass der Browser die Höhe der Seite erst kennt, nachdem sie gerendert wurde.
  • SPAs können manchmal verschachtelte scrollbare Container verwenden, um spezifische Layouts und Funktionen zu erzwingen.

Nicht nur das, sondern es ist auch sehr üblich, dass Anwendungen mehrere scrollbare Bereiche innerhalb einer App haben, nicht nur den Body. Zum Beispiel könnte eine Chat-Anwendung eine scrollbare Seitenleiste und einen scrollbaren Chat-Bereich haben. In diesem Fall möchten Sie die Scroll-Position beider Bereiche unabhängig voneinander wiederherstellen.

Um dieses Problem zu mildern, bietet TanStack Router eine Scroll-Restoration-Komponente und einen Hook, die den Prozess des Überwachens, Zwischenspeicherns und Wiederherstellens von Scroll-Positionen für Sie übernehmen.

Dies geschieht durch

  • Überwachung des DOM auf Scroll-Ereignisse
  • Registrierung von scrollbaren Bereichen im Scroll-Restoration-Cache
  • Lauschen auf die richtigen Router-Ereignisse, um zu wissen, wann Scroll-Positionen zwischengespeichert und wiederhergestellt werden sollen
  • Speichern von Scroll-Positionen für jeden scrollbaren Bereich im Cache (einschließlich window und body)
  • Wiederherstellen von Scroll-Positionen nach erfolgreichen Navigationen vor dem DOM-Paint

Das mag viel klingen, aber für Sie ist es so einfach wie das Folgende

tsx
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  scrollRestoration: true,
})
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  scrollRestoration: true,
})

Hinweis

Die Komponente <ScrollRestoration /> funktioniert immer noch, wurde aber als veraltet markiert.

Benutzerdefinierte Cache-Schlüssel

Aufbauend auf den eigenen Scroll-Restoration-APIs von Remix können Sie auch den Schlüssel anpassen, der zum Zwischenspeichern von Scroll-Positionen für einen bestimmten scrollbaren Bereich verwendet wird, indem Sie die Option getKey verwenden. Dies könnte zum Beispiel verwendet werden, um die gleiche Scroll-Position zu erzwingen, unabhängig vom Browserverlauf des Benutzers.

Die Option getKey empfängt den relevanten Location-Status von TanStack Router und erwartet, dass Sie einen String zurückgeben, um die scrollbaren Messungen für diesen Status eindeutig zu identifizieren.

Der Standard- getKey ist (location) => location.state.__TSR_key!, wobei __TSR_key der eindeutige Schlüssel ist, der für jeden Eintrag im Verlauf generiert wird.

Ältere Versionen, vor v1.121.34, verwendeten state.key als Standard-Schlüssel, dieser wurde jedoch zugunsten von state.__TSR_key veraltet. Vorerst wird location.state.key aus Kompatibilitätsgründen weiterhin verfügbar sein, wird aber in der nächsten Hauptversion entfernt.

Beispiele

Sie könnten das Scrolling mit dem Pfadnamen synchronisieren

tsx
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  getScrollRestorationKey: (location) => location.pathname,
})
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  getScrollRestorationKey: (location) => location.pathname,
})

Sie können Pfade bedingt synchronisieren, dann den Schlüssel für den Rest verwenden

tsx
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  getScrollRestorationKey: (location) => {
    const paths = ['/', '/chat']
    return paths.includes(location.pathname)
      ? location.pathname
      : location.state.__TSR_key!
  },
})
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  getScrollRestorationKey: (location) => {
    const paths = ['/', '/chat']
    return paths.includes(location.pathname)
      ? location.pathname
      : location.state.__TSR_key!
  },
})

Verhindern von Scroll-Restoration

Manchmal möchten Sie möglicherweise verhindern, dass eine Scroll-Restoration stattfindet. Dazu können Sie die Option resetScroll nutzen, die in den folgenden APIs verfügbar ist:

  • <Link resetScroll={false}>
  • navigate({ resetScroll: false })
  • redirect({ resetScroll: false })

Wenn resetScroll auf false gesetzt ist, wird die Scroll-Position für die nächste Navigation nicht wiederhergestellt (bei Navigation zu einem vorhandenen Verlaufseintrag im Stack) oder auf oben zurückgesetzt (bei einem neuen Verlaufseintrag im Stack).

Manuelle Scroll-Restoration

Meistens müssen Sie nichts Besonderes tun, damit die Scroll-Restoration funktioniert. Es gibt jedoch einige Fälle, in denen Sie die Scroll-Restoration manuell steuern müssen. Das häufigste Beispiel sind virtualisierte Listen.

Um die Scroll-Restoration für virtualisierte Listen im gesamten Browserfenster manuell zu steuern

tsx
function Component() {
  const scrollEntry = useElementScrollRestoration({
    getElement: () => window,
  })

  // Let's use TanStack Virtual to virtualize some content!
  const virtualizer = useWindowVirtualizer({
    count: 10000,
    estimateSize: () => 100,
    // We pass the scrollY from the scroll restoration entry to the virtualizer
    // as the initial offset
    initialOffset: scrollEntry?.scrollY,
  })

  return (
    <div>
      {virtualizer.getVirtualItems().map(item => (
        ...
      ))}
    </div>
  )
}
function Component() {
  const scrollEntry = useElementScrollRestoration({
    getElement: () => window,
  })

  // Let's use TanStack Virtual to virtualize some content!
  const virtualizer = useWindowVirtualizer({
    count: 10000,
    estimateSize: () => 100,
    // We pass the scrollY from the scroll restoration entry to the virtualizer
    // as the initial offset
    initialOffset: scrollEntry?.scrollY,
  })

  return (
    <div>
      {virtualizer.getVirtualItems().map(item => (
        ...
      ))}
    </div>
  )
}

Um die Scroll-Restoration für ein bestimmtes Element manuell zu steuern, können Sie den Hook useElementScrollRestoration und das DOM-Attribut data-scroll-restoration-id verwenden.

tsx
function Component() {
  // We need a unique ID for manual scroll restoration on a specific element
  // It should be as unique as possible for this element across your app
  const scrollRestorationId = 'myVirtualizedContent'

  // We use that ID to get the scroll entry for this element
  const scrollEntry = useElementScrollRestoration({
    id: scrollRestorationId,
  })

  // Let's use TanStack Virtual to virtualize some content!
  let virtualizerParentRef: any
  const virtualizer = createVirtualizer({
    count: 10000,
    getScrollElement: () => virtualizerParentRef,
    estimateSize: () => 100,
    // We pass the scrollY from the scroll restoration entry to the virtualizer
    // as the initial offset
    initialOffset: scrollEntry?.scrollY,
  })

  return (
    <div
      ref={virtualizerParentRef}
      // We pass the scroll restoration ID to the element
      // as a custom attribute that will get picked up by the
      // scroll restoration watcher
      data-scroll-restoration-id={scrollRestorationId}
      class="flex-1 border rounded-lg overflow-auto relative"
    >
      ...
    </div>
  )
}
function Component() {
  // We need a unique ID for manual scroll restoration on a specific element
  // It should be as unique as possible for this element across your app
  const scrollRestorationId = 'myVirtualizedContent'

  // We use that ID to get the scroll entry for this element
  const scrollEntry = useElementScrollRestoration({
    id: scrollRestorationId,
  })

  // Let's use TanStack Virtual to virtualize some content!
  let virtualizerParentRef: any
  const virtualizer = createVirtualizer({
    count: 10000,
    getScrollElement: () => virtualizerParentRef,
    estimateSize: () => 100,
    // We pass the scrollY from the scroll restoration entry to the virtualizer
    // as the initial offset
    initialOffset: scrollEntry?.scrollY,
  })

  return (
    <div
      ref={virtualizerParentRef}
      // We pass the scroll restoration ID to the element
      // as a custom attribute that will get picked up by the
      // scroll restoration watcher
      data-scroll-restoration-id={scrollRestorationId}
      class="flex-1 border rounded-lg overflow-auto relative"
    >
      ...
    </div>
  )
}

Scroll-Verhalten

Um das Scroll-Verhalten bei der Navigation zwischen Seiten zu steuern, können Sie die Option scrollRestorationBehavior verwenden. Dies ermöglicht es Ihnen, den Übergang zwischen Seiten sofort statt eines sanften Scrolls zu gestalten. Die globale Konfiguration des Scroll-Restoration-Verhaltens hat dieselben Optionen wie die vom Browser unterstützten, nämlich smooth, instant und auto (weitere Informationen finden Sie auf MDN).

tsx
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  scrollRestorationBehavior: 'instant',
})
import { createRouter } from '@tanstack/solid-router'

const router = createRouter({
  scrollRestorationBehavior: 'instant',
})
Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.