Astro を学んでみる(5)
本記事は、書籍「Astro フロントエンド開発の教科書」によるAstroの勉強、5回目です。
記事内のコードは書籍のものではなく、独自に作成しています。
第4章 ルーティングとレイアウト
4.1 ルーティングとルートパラメータ
ルーティングについては、ファイルベースルーティングです。
フォルダ名、ファイル名によってルーティングを行います。
今回は、4種類のページを作成し、遷移させてみます。
| ページ名 | url | ファイルパス |
| TOPページ | / | pages/index.astro |
| 企業情報ページ | /about/ | pages/about.astro |
| お知らせ一覧ページ | /news/ | pages/news/index.astro |
| お知らせ詳細ページ | /news/ | pages/news/[newsId].astro |
| お知らせ一覧用コンポーネント | ー | components/NewsListItem.astro |
参考書のコードの通りだと冗長ですのでコードは割愛します。
TOPページ

企業情報ページ

お知らせ一覧ページ

お知らせ詳細ページ


4.2 レイアウト機能
4.1 で冗長であったコードを改めます。
インターフェースを別ファイルとします。
export interface News {
id: number;
title: string;
content: string;
}
お知らせデータを別ファイルとします。
[
{
"id": 1,
"title": "お知らせ1",
"content": "本文1"
},
{
"id": 2,
"title": "お知らせ2",
"content": "本文2"
},
{
"id": 3,
"title": "お知らせ3",
"content": "本文3"
}
]個別のお知らせデータを取得する関数を別ファイルとします。
import type {News} from "./interfaces";
import newsList from "./content/newsData.json";
export function getNews(id: number) {
const result = newsList.find((news) => news.id == id);
return result;
}
レイアウトを別ファイルとします。
---
interface Props {
title: string
}
const {title} = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>株式会社XXX | {title}</title>
</head>
<body>
<header>ヘッダーです</header>
<main>
<h1>株式会社XXX</h1>
<p>{title}</p>
<slot />
</main>
<footer>フッターです</footer>
</body>
</html>
<style>
html,
body {
margin: 0;
width: 100%;
height: 100%;
}
body {
margin: 100px;
padding: 20px;
width: 600px;
height: 400px;
border: 1px solid #000;
}
</style>
TOPページをレイアウトを使って構築します。
---
import Layout from "../layouts/Layout2.astro";
const title: string = "トップページです";
---
<Layout title = {title}>
<ul>
<li><a href="/about/">株式会社XXXについて</a></li>
<li><a href="/news/">お知らせ一覧</a></li>
</ul>
</Layout>企業情報ページをレイアウトを使って構築します。
---
import Layout from "../layouts/Layout2.astro";
const title: string = "株式会社XXXについて";
---
<Layout title = {title}>
<p>YYYYYYYYYYYYYYYYY</p>
<p><a href="/">TOPページへ</a></p>
</Layout>
お知らせ一覧ページ
---
import Layout from "../../layouts/Layout2.astro";
const title: string = "お知らせ一覧";
import NewsListItem from "../../components/NewsListItem.astro";
import newsList from "../../content/newsData.json";
---
<Layout title = {title}>
<ul>
{
newsList.map(
(item) => (
<NewsListItem
news={item}
/>
)
)
}
</ul>
</Layout>
お知らせコンポーネント
---
import type {News} from "../interfaces";
interface Props {
news: News;
}
const {news} = Astro.props;
const path = `/news/news-${news.id}`;
---
<li>
<a href={path}>{news.title}</a>
</li>お知らせ詳細ページ
---
import Layout from "../../layouts/Layout2.astro";
const title: string = "お知らせ詳細";
import newsList from "../../content/newsData.json";
import {getNews} from "../../newsList";
// getStaticPaths で動的にルートを生成
export async function getStaticPaths() {
return newsList.map((news) => ({
params: { newsId: news.id },
}));
}
const {newsId} = Astro.params;
const news = getNews(Number(newsId));
---
<Layout title = {title}>
<p>{news.title}</p>
<p>{news.content}</p>
<p><a href="/news/">お知らせ一覧へ</a></p>
<p><a href="/">TOPページへ</a></p>
</Layout>---
import Layout from "../../layouts/Layout2.astro";
const title: string = "お知らせ詳細";
import {newsList, getNews} from "../../newsList";
export function getStaticPaths() {
return [
{params: {newsId: "1"}},
{params: {newsId: "2"}}
]
}
const {newsId} = Astro.params;
// const news = newsList.get(Number(newsId));
const news = getNews(Number(newsId));
---
<Layout title = {title}>
<p>{news.title}</p>
<p>{news.content}</p>
<p><a href="/">TOPページへ</a></p>
</Layout>4.3 ページネーション
ページネーションを利用したページ
---
import Layout from "../../layouts/Layout2.astro";
const title: string = "お知らせ一覧";
import NewsListItem from "../../components/NewsListItem.astro";
import newsList from "../../content/newsData.json";
import type {Page, PagenateFunction} from "astro";
import type {News} from "../../interfaces";
interface Props {
page: Page<News>;
}
export function getStaticPaths({paginate}: {paginate: PaginateFunction}) {
return paginate(newsList, {pageSize: 2});
}
const {page} = Astro.props;
---
<Layout title = {title}>
<p>{page.currentPage}ページ目</p>
<ul>
{
page.data.map(
(item) => (
<NewsListItem
news={item}
/>
)
)
}
</ul>
<div class="pagenation">
{
page.url.prev &&
<p><a href={page.url.prev}>前へ</a></p>
}
{
page.url.next &&
<p><a href={page.url.next}>次へ</a></p>
}
</div>
</Layout>
1ページ目(http://localhost:4321/news/1)

2ページ目(http://localhost:4321/news/2)

