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

Роутинг

Astro использует маршрутизацию на основе файлов для генерации URL ваших сборок на основе структуры файлов в вашем проекте в директории src/pages/.

Astro использует стандартные HTML <a> элементы для навигации между маршрутами. Нет специфического для фреймворка компонента <Link>.

src/pages/index.astro
<p>Узнать больше <a href="/about/">об Astro!</a></p>

.astro компоненты страниц а также Markdown и MDX файлы (.md, .mdx) внутри директории src/pages/ автоматически становятся страницами вашего веб-сайта. Маршрут каждой страницы соответствует ее пути и имени файла в директории src/pages/.

# Пример: Статические маршруты
src/pages/index.astro -> mysite.com/
src/pages/about.astro -> mysite.com/about
src/pages/about/index.astro -> mysite.com/about
src/pages/about/me.astro -> mysite.com/about/me
src/pages/posts/1.md -> mysite.com/posts/1

Файл страницы Astro может указывать динамические параметры маршрута в его имени файла, чтобы генерировать несколько соответствующих страниц. Например, src/pages/authors/[author].astro генерирует страницу биографии для каждого автора на вашем блоге. author становится параметром, который вы можете получить изнутри страницы.

В режиме статического вывода по умолчанию эти страницы генерируются во время сборки, поэтому вы должны предварительно определить список author-ов, которые получат соответствующий файл. В режиме SSR страница будет генерироваться по запросу для любого маршрута, который соответствует.

Поскольку все маршруты должны быть определены во время сборки, динамический маршрут должен экспортировать getStaticPaths(), который возвращает массив объектов со свойством params. Каждый из этих объектов будет генерировать соответствующий маршрут.

[dog].astro определяет динамический параметр dog в его имени файла, поэтому объекты, возвращенные getStaticPaths(), должны включать dog в их params. Затем страница может получить доступ к этому параметру с помощью Astro.params.

src/pages/dogs/[dog].astro
---
export function getStaticPaths() {
return [
{params: {dog: 'clifford'}},
{params: {dog: 'rover'}},
{params: {dog: 'spot'}},
];
}
const { dog } = Astro.params;
---
<div>Хороший пес, {dog}!</div>

Это сгенерирует три страницы: /dogs/clifford, /dogs/rover и /dogs/spot, каждая из которых отображает соответствующее имя собаки.

Имя файла может включать несколько параметров, которые все должны быть включены в объекты params в getStaticPaths():

src/pages/[lang]-[version]/info.astro
---
export function getStaticPaths () {
return [
{params: {lang: 'en', version: 'v1'}},
{params: {lang: 'fr', version: 'v2'}},
];
}
const { lang, version } = Astro.params;
---
...

Это сгенерирует /en-v1/info и /fr-v2/info.

Параметры могут быть включены в отдельные части пути. Например, файл src/pages/[lang]/[version]/info.astro с тем же getStaticPaths() выше сгенерирует маршруты /en/v1/info и /fr/v2/info.

📚 Узнайте больше о getStaticPaths().

Related recipe: Add i18n features (EN)

Если вам нужна большая гибкость в маршрутизации URL, вы можете использовать rest параметр ([...path]) в имени вашего .astro файла для сопоставления путей файлов любой глубины:

src/pages/sequences/[...path].astro
---
export function getStaticPaths() {
return [
{params: {path: 'one/two/three'}},
{params: {path: 'four'}},
{params: {path: undefined }}
]
}
const { path } = Astro.params;
---
...

Это сгенерирует /sequences/one/two/three, /sequences/four, и /sequences. (Установка rest параметра в undefined позволяет ему сопоставиться с страницей верхнего уровня.)

Rest параметры могут быть использованы с другими именованными параметрами. Например, просмотрщик файлов GitHub может быть представлен следующим динамическим маршрутом:

/[org]/[repo]/tree/[branch]/[...file]

В этом примере запрос на /withastro/astro/tree/main/docs/public/favicon.svg будет разбит на следующие именованные параметры:

{
org: 'withastro',
repo: 'astro',
branch: 'main',
file: 'docs/public/favicon.svg'
}

Пример: Динамические страницы на нескольких уровнях

Раздел, озаглавленный Пример: Динамические страницы на нескольких уровнях

В следующем примере rest параметр ([...slug]) и функция props getStaticPaths() генерирует страницы для путей разной глубины.

src/pages/[...slug].astro
---
export async function getStaticPaths() {
const pages = [
{
slug: undefined,
title: "Astro Магазин",
text: "Добро пожаловать в магазин Astro!",
},
{
slug: "products",
title: "Товары Astro",
text: "У нас есть много товаров для вас",
},
{
slug: "products/astro-handbook",
title: "Ультимативное руководство по Astro",
text: "Если вы хотите изучить Astro, вы должны прочитать эту книгу.",
},
];
return pages.map(({ slug, title, text }) => {
return {
params: { slug },
props: { title, text },
};
});
}
const { title, text } = Astro.props;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

В режиме SSR, динамические маршруты определяются таким же образом: включите [param] или [...path] скобки в именах ваших файлов, чтобы соответствовать произвольным строкам или путям. Но поскольку маршруты больше не создаются заранее, страница будет предоставлена для любого соответствующего маршрута. Поскольку это не «статические» маршруты, getStaticPaths не следует использовать.

src/pages/resources/[resource]/[id].astro
---
const { resource, id } = Astro.params;
---
<h1>{resource}: {id}</h1>

Эта страница будет предоставлена для любого значения resource и id: resources/users/1, resources/colors/blue, и т.д.

Поскольку страницы SSR не могут использовать getStaticPaths(), они не могут получать props. Предыдущий пример можно адаптировать для режима SSR, ища значение параметра slug в объекте. Если маршрут находится в корне (”/”), параметр slug будет undefined. Если значение не существует в объекте, мы перенаправляем на страницу 404.

src/pages/[...slug].astro
---
const pages = [
{
slug: undefined,
title: 'Astro Магазин',
text: 'Добро пожаловать в магазин Astro!',
},
{
slug: 'products',
title: 'Товары Astro',
text: 'У нас есть много товаров для вас',
},
{
slug: 'products/astro-handbook',
title: 'Ультимативное руководство по Astro',
text: 'Если вы хотите изучить Astro, вы должны прочитать эту книгу.',
}
];
const { slug } = Astro.params;
const page = pages.find((page) => page.slug === slug);
if (!page) return Astro.redirect("/404");
const { title, text } = page;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

Иногда вам потребуется перенаправить ваших читателей на новую страницу, либо постоянно, потому что структура вашего сайта изменилась, либо в ответ на действие, такое как вход в аутентифицированный маршрут.

Вы можете определить правила для перенаправления пользователей на постоянно перемещенные страницы в вашем конфиге Astro. Или динамическое перенаправление пользователей при использовании вашего сайта.

Настроенные переадресации (экспериментально)

Раздел, озаглавленный Настроенные переадресации (экспериментально)
Добавлено в: astro@2.6.0

После включения экспериментального флага redirects: true, вы можете указать сопоставление постоянных переадресаций в вашем конфигурационном файле Astro. Для большинства переадресаций это сопоставление старого маршрута с новым маршрутом:

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
redirects: true
},
redirects: {
'/old-page': '/new-page'
}
});

Эти переадресации следуют тем же правилам, что и маршруты на основе файлов. Динамические маршруты разрешены, если и новые, и старые маршруты содержат одни и те же параметры, например:

{
"/blog/[...slug]": "/articles/[...slug]"
}

Используя SSR или статический адаптер, вы также можете предоставить объект в качестве значения, позволяющий указать код ответа status в дополнение к новому адресу destination:

import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
redirects: true
},
redirects: {
'/old-page': {
status: 302,
destination: '/new-page'
}
}
});

При запуске astro build, Astro будет выводить HTML-файлы с тегом meta refresh по умолчанию. Поддерживаемые адаптеры вместо этого запишут конфигурационный файл хоста с переадресациями.

Код статуса по умолчанию 301. Если сборка ведется в HTML-файлы, сервер не использует код статуса.

На глобальном Astro, метод Astro.redirect позволяет вам динамически перенаправлять на другую страницу. Вы можете сделать это после проверки того, вошел ли пользователь в систему, получив их сессию из cookie.

src/pages/account.astro
---
import { isLoggedIn } from '../utils';
const cookie = Astro.request.headers.get('cookie');
// Если пользователь не вошел в систему, перенаправьте его на страницу входа
if (!isLoggedIn(cookie)) {
return Astro.redirect('/login');
}
---
<html>
<!-- Страница здесь… -->
</html>

`

Возможно, несколько маршрутов будут соответствовать одному и тому же URL-пути. Например, каждый из этих маршрутов совпадет с /posts/create:

  • Директорияsrc/pages/
    • Директорияposts/
      • create.astro
      • [pid].astro
      • […slug].astro

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

  • Статические маршруты без параметров пути имеют преимущество перед всеми другими маршрутами
  • Динамические маршруты с использованием именованных параметров имеют преимущество перед параметрами rest
  • Предварительно отрендеренные динамические маршруты в приоритете перед динамическими маршрутами сервера
  • Параметры rest имеют наименьший приоритет
  • Конечные точки всегда имеют приоритет над страницами
  • Ничьи разрешаются в алфавитном порядке

Приведя пример выше, вот несколько примеров того, как правила будут сопоставлять запрошенный URL с маршрутом, используемым для построения HTML:

  • pages/posts/create.astro - Строит /posts/create
  • pages/posts/[pid].astro - Строит /posts/1, /posts/abc, и т.д. Но не /posts/create
  • pages/posts/[...slug].astro - Строит /posts/1/2, /posts/a/b/c, и т.д. Но не /posts/create, /posts/1, /posts/abc

Переадресации также следуют тем же правилам, но имеют приоритет в последнюю очередь; если есть маршрут на основе файла и переадресация с тем же уровнем приоритета маршрута, выбирается маршрут на основе файла.

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

Имена маршрутов с пагинацией должны использовать тот же синтаксис [скобок], что и стандартный динамический маршрут. Например, имя файла /astronauts/[page].astro будет генерировать маршруты для /astronauts/1, /astronauts/2, и так далее, где [page] - это сгенерированный номер страницы.

Вы можете использовать функцию paginate() для генерации этих страниц для массива значений следующим образом:

src/pages/astronauts/[page].astro
---
export async function getStaticPaths({ paginate }) {
const astronautPages = [{
astronaut: 'Нил Армстронг',
}, {
astronaut: 'Базз Алдрин',
}, {
astronaut: 'Салли Райд',
}, {
astronaut: 'Джон Гленн',
}];
// Генерация страниц из нашего массива астронавтов, по 2 на страницу
return paginate(astronautPages, { pageSize: 2 });
}
// Все данные с пагинацией передаются на prop "page"
const { page } = Astro.props;
---
<!--Отображение текущего номера страницы. Astro.params.page также можно использовать!-->
<h1>Страница {page.currentPage}</h1>
<ul>
<!--Список из массива информации об астронавтах-->
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>

Это генерирует следующие страницы, с 2 элементами на страницу:

  • /astronauts/1 - Страница 1: Отображает “Нил Армстронг” и “Базз Алдрин”
  • /astronauts/2 - Страница 2: Отображает “Салли Райд” и “Джон Гленн”

Когда вы используете функцию paginate(), каждой странице будут переданы ее данные через prop page. У prop page есть много полезных свойств, но вот самые важные:

  • page.data - массив, содержащий часть данных страницы, которую вы передали функции paginate()
  • page.url.next - ссылка на следующую страницу в наборе
  • page.url.prev - ссылка на предыдущую страницу в наборе
src/pages/astronauts/[page].astro
---
// Генерация пагинированного списка объектов { astronaut }, как в предыдущем примере
export async function getStaticPaths({ paginate }) { /* ... */ }
const { page } = Astro.props;
---
<h1>Страница {page.currentPage}</h1>
<ul>
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>
{page.url.prev ? <a href={page.url.prev}>Предыдущая</a> : null}
{page.url.next ? <a href={page.url.next}>Следующая</a> : null}
interface Page<T = any> {
/** результат */
data: T[];
/** метаданные */
/** номер первого элемента на странице, начиная с 0 */
start: number;
/** номер последнего элемента на странице, начиная с 0 */
end: number;
/** общее количество результатов */
total: number;
/** текущий номер страницы, начиная с 1 */
currentPage: number;
/** количество элементов на странице (по умолчанию: 25) */
size: number;
/** номер последней страницы */
lastPage: number;
url: {
/** url текущей страницы */
current: string;
/** url предыдущей страницы (если таковая имеется) */
prev: string | undefined;
/** url следующей страницы (если таковая имеется) */
next: string | undefined;
};
}

Более продвинутый сценарий использования пагинации - вложенная пагинация. Здесь пагинация сочетается с другими динамическими параметрами маршрута. Вы можете использовать вложенную пагинацию для группировки вашей пагинированной коллекции по некоторому свойству или тегу.

Например, если вы хотите сгруппировать ваши пагинированные посты в Markdown по некоторому тегу, вы должны использовать вложенную пагинацию, создав страницу /src/pages/[tag]/[page].astro, которая будет соответствовать следующим URL:

  • /red/1 (tag=red)
  • /red/2 (tag=red)
  • /blue/1 (tag=blue)
  • /green/1 (tag=green)

Вложенная пагинация работает, возвращая массив результатов paginate() из getStaticPaths(), по одному для каждой группы.

В следующем примере мы реализуем вложенную пагинацию для построения перечисленных выше URL:

src/pages/[tag]/[page].astro
---
export async function getStaticPaths({ paginate }) {
const allTags = ['красный', 'синий', 'зеленый'];
const allPosts = await Astro.glob('../../posts/*.md');
// Для каждого тега возвращаем результат paginate().
// Убедитесь, что вы передаете `{params: {tag}}` в `paginate()`,
// чтобы Astro знал, для какой группы тегов предназначен результат.
return allTags.map((tag) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === tag);
return paginate(filteredPosts, {
params: { tag },
pageSize: 10
});
});
}
const { page } = Astro.props;
const params = Astro.params;

Вы можете исключить страницы или директории из сборки, добавив перед их именами подчеркивание (_). Файлы с префиксом _ не будут распознаваться маршрутизатором и не будут помещены в директорию dist/.

Вы можете использовать это для временного отключения страниц, а также для размещения тестов, утилит и компонентов в той же папке, что и связанные со страницами.

В этом примере только src/pages/index.astro и src/pages/posts/post1.md будут сгенерированы как маршруты страниц и файлы HTML.

  • Директорияsrc/pages/
    • Директория_hidden-directory/
      • page1.md
      • page2.md
    • _hidden-page.astro
    • index.astro
    • Директорияposts/
      • _SomeComponent.astro
      • _utils.js
      • post1.md