Перейти к содержимому

9. Лейауты

Лейауты (layouts) в Qwik City — это компоненты, которые оборачивают страницы и применяются автоматически на основе файловой структуры. Они позволяют создавать общую шапку, навигацию и подвал для группы страниц.

Файл layout.tsx в директории routes/ автоматически применяется ко всем страницам в этой директории:

// src/routes/layout.tsx — применяется ко всем страницам
import { component$, Slot } from '@builder.io/qwik';
export default component$(() => {
return (
<div class="page">
<header>
<nav>
<a href="/">Главная</a>
<a href="/about">О нас</a>
</nav>
</header>
<main>
<Slot /> {/* Здесь рендерится содержимое страницы */}
</main>
<footer>
<p>© 2024 Мой сайт</p>
</footer>
</div>
);
});

<Slot /> — это место для вставки дочернего содержимого. Аналог {children} в React, но работает декларативно:

// Лейаут
export const Card = component$(() => (
<div class="card">
<Slot name="header" /> {/* Именованный слот */}
<div class="card-body">
<Slot /> {/* Дефолтный слот */}
</div>
<Slot name="footer" /> {/* Именованный слот */}
</div>
));
// Использование
export const Page = component$(() => (
<Card>
<div q:slot="header">
<h2>Заголовок карточки</h2>
</div>
<p>Основной контент</p>
<div q:slot="footer">
<button>Действие</button>
</div>
</Card>
));

Лейауты можно вкладывать — каждый уровень директории может иметь свой лейаут:

src/routes/
├── layout.tsx → Корневой лейаут (Header + Footer)
├── index.tsx → / (обёрнут в корневой)
├── blog/
│ ├── layout.tsx → Лейаут блога (Sidebar)
│ ├── index.tsx → /blog (корневой + блог)
│ └── [slug]/
│ └── index.tsx → /blog/:slug (корневой + блог)
└── dashboard/
├── layout.tsx → Лейаут дашборда (Sidebar + Auth)
└── index.tsx → /dashboard (корневой + дашборд)
src/routes/blog/layout.tsx
import { component$, Slot } from '@builder.io/qwik';
export default component$(() => {
return (
<div class="blog-layout">
<aside class="sidebar">
<h3>Категории</h3>
<ul>
<li>JavaScript</li>
<li>Qwik</li>
</ul>
</aside>
<div class="blog-content">
<Slot />
</div>
</div>
);
});

Лейауты могут загружать данные через routeLoader$:

src/routes/layout.tsx
import { component$, Slot } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
export const useCurrentUser = routeLoader$(async ({ cookie }) => {
const token = cookie.get('auth');
if (!token) return null;
return await getUserFromToken(token.value);
});
export default component$(() => {
const user = useCurrentUser();
return (
<div>
<header>
{user.value ? (
<span>Привет, {user.value.name}!</span>
) : (
<a href="/login">Войти</a>
)}
</header>
<Slot />
</div>
);
});

Если страница не должна использовать стандартный лейаут, можно использовать именованный файл [email protected]:

src/routes/
├── layout.tsx → Основной лейаут
├── login/
│ ├── [email protected] → Специальный лейаут для авторизации
│ └── [email protected] → /login (использует layout@auth)

Лейауты могут содержать обработчики ошибок:

// Экспортируй ErrorBoundary из лейаута
export const ErrorBoundary = component$(() => {
const err = useErrorBoundary();
return (
<div class="error">
<h1>Что-то пошло не так</h1>
<p>{err.message}</p>
</div>
);
});