Kurs Svelte i SvelteKit · Moduł 11: Routing w SvelteKit

Layouts

2 min czytania ·
W tej lekcji4

+layout.svelte

<!-- src/routes/+layout.svelte -->
<script>
  import Header from '#lib/components/Header.svelte';
  import Footer from '#lib/components/Footer.svelte';

  let { children } = $props();
</script>

<Header />

<main>
  {@render children()}  <!-- Tu renderuje się strona -->
</main>

<Footer />

<style>
  main {
    max-width: 1200px;
    margin: 0 auto;
    padding: 1rem;
  }
</style>

Layout dostaje zawartość strony jako snippet children i wyświetla ją tagiem {@render children()}. W Svelte 4 służył do tego element <slot />, który w Svelte 5 jest przestarzały.

Alias #lib to w SvelteKit 3 następca $lib: wskazuje folder src/lib (wpis imports w package.json), a moduły JS importujesz z rozszerzeniem, np. #lib/utils.js.

Zagnieżdżone layouty

src/routes/
├── +layout.svelte           # Layout główny
├── +page.svelte             # Strona główna
└── dashboard/
    ├── +layout.svelte       # Layout dla dashboard (zagnieżdżony)
    ├── +page.svelte         # /dashboard
    └── settings/
        └── +page.svelte     # /dashboard/settings
<!-- src/routes/dashboard/+layout.svelte -->
<script>
  import Sidebar from './Sidebar.svelte';

  let { children } = $props();
</script>

<div class="dashboard-layout">
  <Sidebar />
  <div class="content">
    {@render children()}
  </div>
</div>

Layout data

// src/routes/+layout.js
export function load() {
  return {
    user: { name: 'Ragnar' }
  };
}
<!-- src/routes/+layout.svelte -->
<script>
  let { data, children } = $props();
</script>

<nav>
  Zalogowany jako: {data.user.name}
</nav>

{@render children()}

Resetowanie layoutu

<!-- src/routes/fullscreen/+page@.svelte -->
<!-- @ resetuje do layoutu root -->
<h1>Strona pełnoekranowa bez layoutu</h1>
Kod do tej lekcji: App.svelte
<script>
  // Layout i nested layouts

  let showSidebar = $state(true);
</script>

<div class="app-layout">
  <!-- +layout.svelte (główny) -->
  <header class="header">
    <h1>Viking App</h1>
    <nav>
      <a href="/">Home</a>
      <a href="/warriors">Warriors</a>
      <a href="/ships">Ships</a>
    </nav>
  </header>

  <div class="main-content">
    {#if showSidebar}
      <!-- sidebar z (warriors)/+layout.svelte -->
      <aside class="sidebar">
        <h3>Filtr wojowników</h3>
        <ul>
          <li><a href="/warriors?status=all">Wszyscy</a></li>
          <li><a href="/warriors?status=alive">Żywi</a></li>
          <li><a href="/warriors?status=dead">Walhalla</a></li>
        </ul>
      </aside>
    {/if}

    <!-- +page.svelte -->
    <main class="page">
      <button onclick={() => showSidebar = !showSidebar}>
        {showSidebar ? 'Ukryj' : 'Pokaż'} sidebar
      </button>

      <h2>Zawartość strony</h2>
      <p>Tutaj layout renderuje stronę: <code>{'{@render children()}'}</code></p>

      <div class="structure">
        <pre>
src/routes/
├── +layout.svelte        ← Header (wspólny)
├── +page.svelte          ← Home
└── warriors/
    ├── +layout.svelte    ← Sidebar (dla warriors)
    └── +page.svelte      ← Lista wojowników
        </pre>
      </div>
    </main>
  </div>

  <!-- Footer z głównego layoutu -->
  <footer class="footer">
    <p>© 2024 Viking App - Powered by SvelteKit</p>
  </footer>
</div>

<style>
  .app-layout {
    font-family: 'Georgia', serif;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: #0a1628;
    color: #b8d4f7;
  }

  .header {
    background: #1e3a5f;
    padding: 1rem 2rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .header h1 {
    margin: 0;
    color: #ffd700;
    font-size: 1.5rem;
  }

  .header nav {
    display: flex;
    gap: 1rem;
  }

  .header a {
    color: #b8d4f7;
    text-decoration: none;
  }

  .main-content {
    flex: 1;
    display: flex;
  }

  .sidebar {
    width: 200px;
    background: rgba(74, 144, 217, 0.1);
    padding: 1rem;
    border-right: 1px solid #4a90d9;
  }

  .sidebar h3 {
    color: #4a90d9;
    font-size: 1rem;
    margin-top: 0;
  }

  .sidebar ul {
    list-style: none;
    padding: 0;
  }

  .sidebar li {
    margin: 0.5rem 0;
  }

  .sidebar a {
    color: #b8d4f7;
    text-decoration: none;
  }

  .page {
    flex: 1;
    padding: 2rem;
  }

  button {
    padding: 0.5rem 1rem;
    background: #1e3a5f;
    color: #b8d4f7;
    border: 1px solid #4a90d9;
    border-radius: 4px;
    cursor: pointer;
    margin-bottom: 1rem;
  }

  h2 {
    color: #4a90d9;
  }

  code {
    background: rgba(0,0,0,0.5);
    padding: 0.2rem 0.5rem;
    border-radius: 4px;
  }

  .structure pre {
    background: rgba(0,0,0,0.5);
    padding: 1rem;
    border-radius: 4px;
    font-size: 0.85rem;
  }

  .footer {
    background: #1e3a5f;
    padding: 1rem;
    text-align: center;
    font-size: 0.9rem;
  }
</style>

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak w +layout.svelte (Svelte 5) wyświetlasz zawartość strony?

Przydatne artykuły