3. Astro-компоненты (.astro)
Компонент .astro — это основная единица UI в Astro. По синтаксису он напоминает обычный HTML-файл, расширенный возможностями JavaScript и CSS, но с ключевым отличием: весь JavaScript выполняется только на сервере.
Структура .astro файла
Заголовок раздела «Структура .astro файла»Каждый .astro файл состоит из трёх частей:
---// 1. FRONTMATTER — серверный JavaScript// Всё здесь выполняется при сборке или на сервереimport Component from './Component.astro';const message = 'Привет, Astro!';const items = [1, 2, 3];---
<!-- 2. ШАБЛОН — HTML с выражениями --><div class="container"> <h1>{message}</h1> <ul> {items.map(item => <li>{item}</li>)} </ul> <Component /></div>
<style> /* 3. СТИЛИ — изолированные CSS */ .container { padding: 1rem; }</style>Три разделителя --- обрамляют frontmatter — это синтаксис, знакомый по Markdown.
Frontmatter: серверный JavaScript
Заголовок раздела «Frontmatter: серверный JavaScript»Код в frontmatter выполняется только на сервере. Здесь можно:
---// Импортыimport Layout from '../layouts/Layout.astro';import Button from '../components/Button.astro';import type { ImageMetadata } from 'astro';
// Работа с даннымиconst response = await fetch('https://api.example.com/posts');const posts = await response.json();
// Условная логикаconst isLoggedIn = Astro.cookies.get('session')?.value;const user = isLoggedIn ? await getUser() : null;
// Работа с пропсамиconst { title, description = 'По умолчанию' } = Astro.props;
// Работа с URLconst currentPath = Astro.url.pathname;---Важно: этот код не попадёт в браузер. Даже console.log в frontmatter выводит сообщение только в терминале, не в браузере.
Шаблон: HTML с выражениями
Заголовок раздела «Шаблон: HTML с выражениями»Шаблон — это расширенный HTML. В нём можно использовать JSX-подобные выражения:
---const name = 'Мир';const isAdmin = true;const colors = ['красный', 'зелёный', 'синий'];const url = 'https://astro.build';---
<!-- Вывод переменных --><h1>Привет, {name}!</h1>
<!-- Условный рендеринг -->{isAdmin && <span class="badge">Администратор</span>}{isAdmin ? <p>Панель управления</p> : <p>Нет доступа</p>}
<!-- Рендеринг списков --><ul> {colors.map(color => ( <li class="color-item">{color}</li> ))}</ul>
<!-- Атрибуты из переменных --><a href={url} target="_blank">Сайт Astro</a>
<!-- Класс из условия --><div class:list={['base', isAdmin && 'admin', 'container']}> Контент</div>Пропсы (Props)
Заголовок раздела «Пропсы (Props)»Компоненты Astro принимают пропсы через Astro.props. Для типизации используйте интерфейс:
---// Определяем типы пропсовinterface Props { title: string; subtitle?: string; count: number; variant?: 'primary' | 'secondary';}
// Деструктурируем пропсыconst { title, subtitle, count, variant = 'primary' } = Astro.props;---
<div class={'card card--' + variant}> <h2>{title}</h2> {subtitle && <p>{subtitle}</p>} <span class="count">{count}</span></div>Использование компонента:
---import Card from '../components/Card.astro';---
<Card title="Привет" count={42} variant="primary" /><Card title="Мир" subtitle="Описание" count={7} />Слоты (Slots)
Заголовок раздела «Слоты (Slots)»Слоты позволяют передавать HTML-контент в компонент — аналог children в React:
---const { variant = 'primary' } = Astro.props;---<button class={'btn btn--' + variant}> <slot /> <!-- Сюда вставится переданный контент --></button><!-- Использование --><Button variant="primary"> Нажми меня 🚀</Button>
<Button variant="secondary"> <span>Иконка</span> Текст с иконкой</Button>Именованные слоты
Заголовок раздела «Именованные слоты»<div class="card"> <header> <slot name="header" /> <!-- Именованный слот --> </header> <main> <slot /> <!-- Дефолтный слот --> </main> <footer> <slot name="footer" /> </footer></div><Card> <h2 slot="header">Заголовок карточки</h2> <p>Основной контент карточки</p> <Button slot="footer">Подробнее</Button></Card>Scoped стили
Заголовок раздела «Scoped стили»CSS в <style> блоке автоматически изолируется для текущего компонента:
<div class="title">Заголовок</div><p class="text">Текст</p>
<style> /* Эти стили применяются ТОЛЬКО к этому компоненту */ .title { color: #FF5D01; font-size: 2rem; }
.text { color: #64748b; }</style>Astro добавляет уникальный атрибут data-astro-cid-xxxxxxxx к элементам, обеспечивая изоляцию стилей без CSS Modules или styled-components.
Для глобальных стилей используйте :global():
<style> /* Только для этого компонента */ .button { background: #FF5D01; }
/* Глобальный стиль */ :global(.reset) { margin: 0; padding: 0; }</style>Объект Astro
Заголовок раздела «Объект Astro»В frontmatter доступен глобальный объект Astro:
---// URL текущей страницыconst url = Astro.url; // URL objectconst path = Astro.url.pathname; // '/blog/post-1'
// Параметры запросаconst params = Astro.params; // { slug: 'post-1' }
// Кукиconst cookie = Astro.cookies.get('name')?.value;
// Заголовки запроса (только при SSR)const userAgent = Astro.request.headers.get('user-agent');
// Перенаправлениеif (!isLoggedIn) { return Astro.redirect('/login');}---Интерактивный конструктор компонентов
Заголовок раздела «Интерактивный конструктор компонентов»Исследуйте разные примеры .astro компонентов. Переключайтесь между вкладками: