Динамические маршруты
Динамический маршрут — страница, у которой часть адреса меняется: /posts/first-post, /posts/learning-astro. Параметр пишут в имени файла в квадратных скобках. Поскольку статический сайт собирается заранее, Astro должен знать все возможные значения параметра — их возвращает функция getStaticPaths().
Страница статьи
Удалите src/pages/posts/first-post.astro и создайте src/pages/posts/[id].astro:
---
import { getCollection, render } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { id: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<BaseLayout title={post.data.title}>
<h1>{post.data.title}</h1>
<p>{post.data.pubDate.toLocaleDateString('ru-RU')}</p>
<Content />
</BaseLayout>Откройте /posts/first-post и /posts/learning-astro — обе страницы собраны из одного файла. Ссылки на них уже есть в списке /posts.
Как это работает
getStaticPaths() возвращает массив объектов, по одному на страницу:
| Поле | Что в нём |
|---|---|
params | Значения параметров адреса: { id: 'first-post' } даёт /posts/first-post |
props | Данные, которые страница получит в Astro.props |
Значения параметров доступны и в Astro.params, например Astro.params.id. При сборке Astro вызовет функцию один раз и создаст по HTML-файлу на каждый элемент массива.
Страница тега
Тот же приём делает страницы тегов. Создайте src/pages/tags/[tag].astro:
---
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import PostCard from '../../components/PostCard.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
const tags = [...new Set(posts.flatMap((post) => post.data.tags))];
return tags.map((tag) => ({
params: { tag },
props: { posts: posts.filter((post) => post.data.tags.includes(tag)) },
}));
}
const { tag } = Astro.params;
const { posts } = Astro.props;
---
<BaseLayout title={`Тег ${tag}`}>
<h1>Статьи с тегом «{tag}»</h1>
{posts.map((post) => <PostCard title={post.data.title} url={`/posts/${post.id}`} />)}
</BaseLayout>Set убирает повторы, и для каждого тега получается своя страница. Откройте /tags/astro — там будут только статьи с тегом astro. Ссылку на тег можно вывести в статье: <a href={'/tags/' + tag}>.
Несколько сегментов
Параметр с тремя точками, [...slug].astro, захватывает адрес любой глубины: /docs/a/b/c. Он нужен, когда записи лежат во вложенных папках.
Частая ошибка
В params кладут значение, которое не совпадает с ссылками на сайте, например заголовок статьи с пробелами вместо id. Страница собирается по одному адресу, а ссылки ведут на другой, и посетитель видит 404. Берите для адреса одно и то же поле — post.id — и в getStaticPaths(), и в ссылках.