Пропустить до содержимого

Компоненты

Компоненты Astro являются основными строительными блоками любого проекта Astro. Они представляют собой HTML шаблоны, которые не требуют выполнения на стороне клиента. Определить компонент Astro можно по расширению файла: .astro.

Компоненты Astro чрезвычайно гибки. Часто компонент Astro будет содержать некоторый повторно используемый UI на странице, например заголовок или карточку профиля. В других случаях компонент Astro может содержать небольшой фрагмент HTML, например набор общих <meta> тегов, которые упрощают работу с SEO. Компоненты Astro могут даже содержать макет страницы целиком.

Самое главное, что нужно знать о компонентах Astro, - это то, что они не отрисовываются на клиенте. Они преобразуются в HTML либо во время сборки, либо с использованием рендеринга на стороне сервера (SSR). Вы можете включить JavaScript-код внутри вашего компонента frontmatter, и он весь будет удален с конечной страницы, отправленной в браузеры ваших пользователей. В результате получается более быстрый сайт с нулевым использованием JavaScript по умолчанию.

Когда вашему компоненту Astro действительно требуется интерактивность на стороне клиента, вы можете добавить стандартные теги HTML <script> или компоненты UI фреймворков.

Компонент Astro состоит из двух основных частей: Скрипта компонента и Шаблона компонента. Каждая часть выполняет свою работу, но вместе они обеспечивают структуру, которая одновременно проста в использовании и достаточно выразительна, чтобы справиться с тем, что вы захотите создать.

src/components/EmptyComponent.astro
---
// Скрипт компонента (JavaScript)
---
<!-- Шаблон компонента (HTML + выражения JS) -->

Astro использует ограждение кода (---) для идентификации скрипта в вашем компоненте Astro. Если вы когда-либо писали Markdown раньше, возможно, вы уже знакомы с похожей концепцией, называемой frontmatter. Идея Astro о скрипте компонента была непосредственно вдохновлена этой концепцией.

Вы можете использовать скрипт компонента для написания любого кода JavaScript, необходимого для визуализации шаблона. Это может включать в себя:

  • импорт других Astro компонентов
  • импорт компонентов из других фреймворков, таких как React
  • импорт данных, например файла JSON
  • получение контента из API или базы данных
  • создание переменных, на которые вы будете ссылаться в своем шаблоне
src/components/MyComponent.astro
---
import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeReactComponent.jsx';
import someData from '../data/pokemon.json';
// Доступ к входным параметрам компонента, таким как `<X title="Hello, World" />`
const {title} = Astro.props;
// Получение внешних данных, даже из приватного API или базы данных
const data = await fetch('SOME_SECRET_API_URL/users').then(r => r.json());
---
<!-- Здесь ваш шаблон! -->

Ограждение кода предназначено для того, чтобы гарантировать, что JavaScript, который вы пишете в нем, не ускользнет в ваше внешнее приложение и не попадет в руки вашего пользователя. Вы можете безопасно писать здесь ресурсоёмкий или конфиденциальный код (например, вызов вашей личной базы данных), не беспокоясь о том, что он когда-либо попадет в браузер вашего пользователя.

Шаблон компонента находится под ограждением кода и определяет вывод HTML вашего компонента.

Если вы напишете здесь простой HTML, ваш компонент будет отображать этот HTML на любой странице Astro, в которую он импортирован и используется.

Однако, синтаксис Astro так же поддерживает JavaScript выражения, Astro <style> и <script> теги, импортированные компоненты, и специальные Astro директивы. Данные и значения, определенные в скрипте компонента, можно использовать в шаблоне компонента для создания динамически создаваемого HTML.

src/components/MyFavoritePokemon.astro
---
// Здесь ваш скрипт компонента!
import Banner from '../components/Banner.astro';
import ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';
const myFavoritePokemon = [/* ... */];
const { title } = Astro.props;
---
<!-- Поддерживаются HTML коментарии! -->
{/* JS comment syntax is also valid! */}
<Banner />
<h1>Hello, world!</h1>
<!-- Используйте входные параметры и другие переменные из скрипта компонента.: -->
<p>{title}</p>
<!-- Включите другие компоненты инфраструктуры пользовательского интерфейса с помощью директивы `client`: для гидратации: -->
<ReactPokemonComponent client:visible />
<!-- Смешивайте HTML с выражениями JavaScript, аналогично JSX.: -->
<ul>
{myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>
<!-- Используйте директиву шаблона для создания имен классов из нескольких строк или даже объектов! -->
<p class:list={["add", "dynamic", {classNames: true}]} />

Компоненты спроектированы так, чтобы их можно было повторно использовать и компоновать. Вы можете использовать компоненты внутри других компонентов для создания более продвинутого пользовательского интерфейса. Например, компонент Button можно использовать для создания компонента ButtonGroup:

src/components/ButtonGroup.astro
---
import Button from './Button.astro';
---
<div>
<Button title="Button 1" />
<Button title="Button 2" />
<Button title="Button 3" />
</div>

Компонент Astro может определять и принимать параметры. Эти входные параметры затем становятся доступными для шаблона компонента для рендеринга HTML. Входные параметры доступны в глобальном объекте Astro.props в вашем скрипте.

Вот пример компонента, который получает входные параметры greeting и name. Обратите внимание, что получаемые входные параметры деструктурированы из глобального объекта Astro.props.

src/components/GreetingHeadline.astro
---
// Применение: <GreetingHeadline greeting="Howdy" name="Partner" />
const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

Этот компонент при импорте и визуализации в других компонентах Astro, макетах или страницах может передавать эти параметры в качестве атрибутов:

src/components/GreetingCard.astro
---
import GreetingHeadline from './GreetingHeadline.astro';
const name = "Astro"
---
<h1>Greeting Card</h1>
<GreetingHeadline greeting="Hi" name={name} />
<p>I hope you have a wonderful day!</p>

Вы также можете определить свои входные параметры с помощью TypeScript с интерфейсом типа Props. Astro автоматически подхватит интерфейс Props в вашем frontmatter и выдаст предупреждения/ошибки типа. Этим входным параметрам также могут быть присвоены значения по умолчанию при деструктуризации из Astro.props.

src/components/GreetingHeadline.astro
---
interface Props {
name: string;
greeting?: string;
}
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

Свойствам компонента могут быть присвоены значения по умолчанию, которые можно использовать, если они не указаны.

src/components/GreetingHeadline.astro
---
const { greeting = "Hello", name = "Astronaut" } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

<slot /> это заполнитель для внешнего HTML-содержимого, позволяющий вставлять дочерние элементы из других файлов в шаблон компонента.

По умолчанию все дочерние элементы, переданные компоненту, будут отображаться в его <slot />

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props
---
<div id="content-wrapper">
<Header />
<Logo />
<h1>{title}</h1>
<slot /> <!-- дочерний элемент будет здесь -->
<Footer />
</div>
src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
<h2>All about Fred</h2>
<p>Here is some stuff about Fred.</p>
</Wrapper>

Этот шаблон является основой Astro Макетов: целая страница HTML-контента может быть «обернута» тегами <SomeLayoutComponent></SomeLayoutComponent> и передана компоненту для отрисовки внутри определенных в нем общих элементов страницы.

Компонент Astro также может иметь именованные слоты. Это позволяет передавать в местоположение слота только элементы HTML с соответствующим именем слота.

Слоты именуются с помощью атрибута name:

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props
---
<div id="content-wrapper">
<Header />
<slot name="after-header"/> <!-- дочерние элементы с атрибутом `slot="after-header"` будут находиться здесь -->
<Logo />
<h1>{title}</h1>
<slot /> <!-- дочерние элементы без `slot`, или с `slot="default"` будут находиться здесь -->
<Footer />
<slot name="after-footer"/> <!-- дочерние элементы с атрибутом `slot="after-footer"` будут находиться здесь -->
</div>

Чтобы внедрить HTML-контент в определенный слот, используйте атрибут slot в любом дочернем элементе, чтобы указать имя слота. Все остальные дочерние элементы компонента будут вставлены в стандартный (безымянный) <slot />.

src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
<img src="https://my.photo/fred.jpg" slot="after-header">
<h2>All about Fred</h2>
<p>Here is some stuff about Fred.</p>
<p slot="after-footer">Copyright 2022</p>
</Wrapper>

Чтобы передать несколько HTML-элементов в заполнитель <slot/> компонента без обёртывающего <div>, используйте атрибут slot="" на компоненте <Fragment/> Astro:

src/components/CustomTable.astro
---
// Создание пользовательской таблицы с именованными заполнителями для заголовка и тела контента
---
<table class="bg-white">
<thead class="sticky top-0 bg-white"><slot name="header" /></thead>
<tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="body" /></tbody>
</table>

Вставьте несколько строк и столбцов HTML-контента с помощью атрибута slot="", чтобы указать содержимое "header" и "body". Отдельные элементы HTML также можно стилизовать:

src/components/StockTable.astro
---
import CustomTable from './CustomTable.astro';
---
<CustomTable>
<Fragment slot="header"> <!-- pass table header -->
<tr><th>Product name</th><th>Stock units</th></tr>
</Fragment>
<Fragment slot="body"> <!-- pass table body -->
<tr><td>Flip-flops</td><td>64</td></tr>
<tr><td>Boots</td><td>32</td></tr>
<tr><td>Sneakers</td><td class="text-red-500">0</td></tr>
</Fragment>
</CustomTable>

Обратите внимание, что именованные слоты должны быть непосредственными дочерними элементами компонента. Вы не можете передавать именованные слоты через вложенные элементы.

Слоты также могут отображать резервный контент. Когда в слот не передаются соответствующие дочерние элементы, элемент <slot /> отобразит свои собственные дочерние элементы-заполнители.

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props
---
<div id="content-wrapper">
<Header />
<Logo />
<h1>{title}</h1>
<slot>
<p>Это резервное содержимое, если в слот не передан дочерний элемент</p>
</slot>
<Footer />
</div>

Слоты можно передавать другим компонентам. Например, при создании вложенных макетов:

src/layouts/BaseLayout.astro
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<slot name="head"/>
</head>
<body>
<slot />
</body>
</html>
src/layouts/HomeLayout.astro
---
import BaseLayout from "./BaseLayout.astro";
---
<BaseLayout>
<slot name="head" slot="head"/>
<slot />
</BaseLayout>

Теперь содержимое стандартного(безымянного) слота и слота head, переданных в HomeLayout, будет перенесено в родительский компонент BaseLayout.

src/pages/index.astro
---
import HomeLayout from "../layouts/HomeLayout.astro";
---
<HomeLayout>
<title slot="head">Astro</title>
<h1>Astro</h1>
</HomeLayout>

Astro поддерживает импорт и использование .html файлов в качестве компонентов или размещение этих файлов в подкаталоге src/pages/ в качестве страниц. Возможно, вам захочется использовать HTML-компоненты, если вы повторно используете код с существующего сайта, созданного без фреймворка, или если вы хотите убедиться, что ваш компонент не имеет динамических функций.

HTML-компоненты должны содержать только валидный HTML, поэтому они лишены ключевых возможностей компонентов Astro:

Узнайте больше об использовании UI компонентов фреймворков в вашем проекте Astro.