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

Компоненты

Компоненты 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.