Powrót do strony głównej

Przycisk «Wstecz» w Vue: prawidłowa implementacja

Przewodnik techniczny po poprawnej implementacji przycisku «Wstecz» w aplikacjach na Vue.js. Omawiane są błędy użycia router.push(), proponowane rozwiązania dla edge cases i uniwersalny komponent z fallback i potwierdzeniem.

Przycisk «Wstecz» w Vue: pułapki i rozwiązanie
Advertisement 728x90

# Jak poprawnie zaimplementować przycisk „Wstecz” w Vue: przewodnik techniczny dla deweloperów

Implementacja przycisku „Wstecz” w aplikacjach na Vue.js często wydaje się trywialna, ale w praktyce prowadzi do poważnych problemów z nawigacją i historią przeglądarki. Wielu deweloperów błędnie używa router.push() zamiast metod przeznaczonych do poruszania się po istniejącym stosie historii. To tworzy duplikujące się wpisy, psuje zachowanie przeglądarkowego przycisku „Wstecz” i generuje nieskończone pętle przejść. W tym artykule — technicznie precyzyjny przewodnik po poprawnej implementacji przycisku „Wstecz” z uwzględnieniem edge cases i doświadczenia użytkownika.

Dlaczego router.push() — to nie „wstecz"

Metoda router.push() dodaje nowy wpis do historii przeglądarki. Służy do przejścia do przodu na nowy trasa, nawet jeśli ten trasa był już wcześniej odwiedzony. W przeciwieństwie do niej, router.back() i router.go(-1) nie tworzą nowych wpisów — po prostu przesuwają wskaźnik po już istniejącym stosie historii.

Gdy używasz router.push() dla przycisku „Wstecz”, w rzeczywistości symulujesz przejście do przodu, maskując je jako powrót. Prowadzi to do następującej sekwencji:

Google AdInline article slot
  • Użytkownik: Strona główna → Lista produktów → Produkt A
  • Kliknięcie twojego przycisku „Wstecz” z router.push('/list')
  • Historia staje się: Strona główna → Lista produktów → Produkt A → Lista produktów (duplikat)

Teraz, jeśli użytkownik kliknie przycisk „Wstecz” w przeglądarce, wróci na stronę „Produkt A”, a nie na „Stronę główną". Przy ponownym kliknięciu twojego przycisku ponownie zadziała push, i cykl się powtórzy.

Podstawowe metody nawigacji w Vue Router

Vue Router udostępnia trzy kluczowe metody do zarządzania historią:

  • router.push(location) — dodaje nowy wpis do historii.
  • router.replace(location) — zastępuje bieżący wpis bez dodawania nowego.
  • router.back() / router.go(-1) — przesuwa się wstecz po istniejącej historii.

Dla przycisku „Wstecz” w interfejsie jedynym poprawnym wyboremrouter.back() lub router.go(-1). W pełni odpowiadają one zachowaniu przeglądarkowego przycisku i nie naruszają spójności stosu.

Google AdInline article slot

Obsługa edge cases: gdy historii brak

W praktyce użytkownicy często trafiają na stronę bezpośrednio — przez zewnętrzną linkę, odświeżenie strony lub po zamknięciu karty. W takich sytuacjach stos historii może być pusty lub zawierać tylko jeden wpis. Wywołanie router.back() nie spowoduje błędu, ale nic się nie stanie, co pozostawi użytkownika w zawieszeniu.

Aby temu zapobiec, należy przewidzieć zapasowy trasa (fallbackRoute). Logika powinna sprawdzać możliwość powrotu i, w razie jej braku, przekierowywać na bezpieczny trasa — na przykład na stronę główną lub sekcję nadrzędną.

Uniwersalny komponent przycisku „Wstecz"

Poniżej — przykład komponentu gotowego do produkcji, z obsługą wszystkich niezbędnych scenariuszy:

Google AdInline article slot
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter, useRoute, type RouteLocationRaw } from 'vue-router'

const props = defineProps<{
  fallbackRoute?: RouteLocationRaw
  beforeNavigate?: () => boolean | Promise<boolean>
  beforeRouterPush?: () => void
}>()

const router = useRouter()
const route = useRoute()

const isSamePage = computed<boolean>(() => {
  const fromRoute = router.options.history.state?.back

  if (!fromRoute || typeof fromRoute !== 'string') return false

  const currentPrefix = route.path.split('/')[1]
  const fromPrefix = fromRoute.split('/')[1]

  return currentPrefix === fromPrefix
})

const goBack = async () => {
  if (props.beforeNavigate) {
    const shouldProceed = await props.beforeNavigate()
    if (!shouldProceed) return
  }

  if (props.beforeRouterPush) {
    props.beforeRouterPush()
    return
  }

  if (isSamePage.value) {
    router.back()
  } else if (props.fallbackRoute) {
    void router.push(props.fallbackRoute)
  } else {
    void router.push({ name: 'home' })
  }
}
</script>

<template>
  <q-btn
    icon="arrow_back"
    @click="goBack"
    aria-label="Onzad"
  />
</template>

Ten komponent rozwiązuje kilka zadań jednocześnie:

  • Obsługuje potwierdzenie przed odejściem (np. zapisanie szkicu)
  • Rozróżnia przejścia wewnętrzne i zewnętrzne po prefiksach URL
  • Przewiduje zapasowy trasa
  • Pozwala na pełne nadpisanie logiki w razie potrzeby

Co ważne

  • Nie używaj router.push() dla przycisku „Wstecz” — narusza to model historii przeglądarki.
  • Zawsze przewiduj zapasowe zachowanie na wypadek bezpośredniego wejścia.
  • Sprawdzaj kontekst przejścia: powrót wewnątrz sekcji i powrót z zewnątrz wymagają innej logiki.
  • Obsługuj anulowanie przejścia przez asynchroniczne haki — to kluczowe dla formularzy i edytorów.
  • Synchronizuj zachowanie z natywnym przyciskiem przeglądarki — użytkownik nie powinien zauważyć różnicy.

— Editorial Team

Advertisement 728x90

Czytaj dalej