@page · Layout · NavMenu

Routing og SPA

Flere «sider» i én Blazor-app med routing, deep links, query strings og NavLink — SPA uden fuld page reload.

Læringsmål

Hvornår bruger I routing? Så snart appen har mere end én «skærm» — Pokémon-liste, LoL, indstillinger, login — uden at brugeren skal gennemleve fuld page reload og tabe Blazor-circuit.

Tjek dig selv før du går videre

  • Du bruger NavLink med active styling.
  • Du forstår at routing ikke reloader hele siden.
  • Du har prøvet SPA-anim lab.

En SPA loader shell én gang. Blazor router matcher URL til komponent, skifter indhold i @Body, bevarer layout og DI-scope (afhængigt af hosting).

SPA uden page-reload

Klik i «navbaren» — kun midterindholdet skifter. Shell (layout) bliver.

Velkommen

MainLayout + NavMenu omslutter alle sider.

@page "/pokemon"

HttpClient henter data — URL skifter, ingen fuld reload.

@page "/status"

Deep link kan deles — samme app i hukommelsen.

@page "/pokemon"
@page "/dex"
@layout MainLayout

<PageTitle>Pokédex</PageTitle>
<h1>Pokémon</h1>
<NavLink class="nav-link" href="pokemon" Match="NavLinkMatch.Prefix">
  Pokémon
</NavLink>
<NavLink class="nav-link" href="lol">
  LoL
</NavLink>

Match="All" (default) kræver præcis path; Prefix matcher understier.

Hvornår NavLink? Al intern navigation i MainLayout — demo-hub, teori, jeres egne @page-ruter. Eksterne links (Mercantec Auth, katalog på andet domæne) forbliver almindelige <a target="_blank"> med rel="noreferrer" hvor relevant.

Query parameters

Skriv et søgenavn

Se URL og Razor-kode opdatere live — samme mønster som /pokemon?name=.


@page "/soeg"

<p>Søger efter: @name</p>

@code {
  [SupplyParameterFromQuery]
  public string? Name { get; set; }

  protected override async Task OnParametersSetAsync()
  {
    if (!string.IsNullOrWhiteSpace(Name))
      await SearchAsync(Name);
  }
}

URL /soeg?name=charizard kan bookmarkes og deles — god UX til API-søgning.

Hvornår query frem for route? Valgfri filtre (søgning, sortering, side) der ikke definerer «hvilken entitet» — fx /pokemon?name=pika. Obligatorisk id i path: /pokemon/25 er tydeligere deep link end kun query.

// Opdatér query uden fuld reload
_nav.NavigateTo($"/soeg?name={Uri.EscapeDataString(filter)}");

Route parameters

@page "/pokemon/{id:int}"

<h1>Detail #@Id</h1>

@code {
  [Parameter] public int Id { get; set; }
}

Hvornår route constraints? {id:int} afviser ikke-numeriske URLs tidligt — undgår unødige API-kald med NaN. LoL champion-id som string: {slug} uden int-constraint.

Layouts

MainLayout.razor indeholder fælles chrome; sider sætter @layout eller arver default fra Routes.razor.

NotFound: I Routes.razor eller router-konfiguration — vis venlig 404-side når ingen @page matcher (fx bruger skriver /pokmon). Link tilbage til forsiden; log ikke staktrace i UI.

<Router AppAssembly="typeof(Program).Assembly" NotFound="typeof(Pages.NotFound)">
  ...
</Router>

Faldgrube: At bruge plain <a href> uden Blazor router — fuld reload, tab af circuit state på Server. Brug NavLink eller NavigationManager.

Fordele SPA: hurtig navigation, genbrug af services/state, én codebase.
Ulemper: større initial load (især WASM), SEO kræver plan, auth tokens håndteres i klient.

Quiz 1

Hvad gør NavLink frem for et almindeligt anchor-tag i Blazor?

Quiz 2

Hvordan binder I ?name= til en property (.NET 8+)?

Hvorfor det betyder noget: SPA-routing holder Mercantec Auth state og HttpClient alive — fuld page reload mister session.

Sådan fejler det i praksis: Almindelige <a href> uden NavLink — hel side reload, langsomt, taber Blazor state.

Mini-opgave

Routes /pokemon og /lol med NavLink; bekræft kun @Body skifter.

Quiz 3

Intern navigation i Blazor SPA?

Læs hos Microsoft

Prøv med API

  • Lav sider /pokemon, /minecraft, /starwars — samme mønster som demo-hubben.
  • Tilføj query-søgning /pokemon?name= der kalder OpgaverAPI.
16475 #1216475 #1316475 #14

Baseret på MAGS Blazor-wiki og Microsoft Learn — Blazor.