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

\ 最新情報をチェック /

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA