webコーダーのsaco @sacocco_sacoya です。
前回に引き続きはじめてつくるNuxtサイト(三好アキさん著書)で学んだことを記事にします。
教材内の目次では第2章の「記事一覧ページの作成」の記録です!
内容はNuxt.js3でブログ記事一覧ページを作成する、というものです。
生じた疑問点やエラー、教材と結果が違う箇所など、私が触ってみた結果も交えて記述していきたいと思います。
↓前回の記事はこちら
記事一覧ページの作成
前回はブログページとなるblog.vueファイルを作成しました。
ブログはマークダウン形式で作成していきます!
ブログを作成する為に必要なもの
- ブログページ(blog.vue)
- それぞれの記事データ(マークダウンファイル)
- 記事データをblog.vueに取り込んで表示する仕組み
記事データを作成
ルートディレクトリに、contentフォルダを作成し、さらにその中へblogフォルダを作成します。
blogフォルダの中へ first-blog.md として、マークダウンファイルを作成します。
拡張子「.md」がマークダウン形式のファイルです。
first-blog.mdの中へ以下のように記述しました。
//first-blog.md
//Frontmatter
---
id:"1"
title:"1つ目の記事"
date:"20xx-03-01"
image:""
excerpt:""
---
//Frontmatter ここまで
これが1つ目の記事です。//本文
マークダウンの記述方法
ハイフン3つで挟まれた部分がFrontmatterというもので、記事のタイトルなど、必要な情報を追加していきます。
本文はFrontmatterの下に記述していきます。
マークダウンファイル1つに対し、1つのブログ記事となります。
教材に合わせて6つ記事を作成しました。
※各.mdファイルのidや日付、タイトルをそれぞれ該当の数字に変更しています。
!注意点
マークダウンファイル作成時の注意点として、教材内で「//first-blog.md」と書かれていたものをそのまま記述していたことが原因で出力時にエラーになりました。
Frontmatterから記述を開始したことでエラーが解消されました。
↓これはダメな例。
ブログ記事データを取り込む下準備
作成したブログ記事を、blog.vueに取り込むための下準備としてNuxt ContentというNuxt専用のパッケージを使用します。
Nuxt Contentとは
Nuxt Contentを使用することで、様々な形式のデータをNuxtに読み込んで利用できるようになります。
また、Nuxt Contentは、contentフォルダ内のデータを自動で読み取ってくれる仕組みを持つパッケージです。
contentフォルダを作成し、この中にブログ記事を作成したのはこのためです。
Nuxt Contetをインストール
ターミナルを開き、Nuxtを起動中であれば(^+C)で終了し、以下のコマンドを入力します。
npm install -D @nuxt/content
※このコマンドの-Dは、devDevdependenciesに保存するための設定で、–save-devと書かれることもあります。
devDevdependenciesのdevはdevelopment(開発)の略で、開発時に必要なパッケージをインストールする際に使用されるものです。
インストール完了後、package-lock.jsonを開くと、devDependenciesの項目に@nuxt/contentが追加されていました。
※教材ではpackage.jsonとなっていましたが、私のダウンロードした環境ではpackage-lock.jsonとなっていました。
Nuxt Contentを利用するには、nuxt.config.tsのdefineNuxtConfig内に、以下の設定を記述する必要があります。
modules: [
"@nuxt/content",
],
※devtoolsの波括弧のあとにカンマが必要なので注意です。
これで下準備ができました!
blog.vueに記事データを取り込む
他のVueフレームワークでは、ブログ記事読み込みに複雑なコード指定が必要になるようですが、Nuxt Contentを使用すれば簡単に進めていくことができるようです。
前回記述した<h1>やCSSなどの不要な記述は削除し、<script setup>内に、以下のコードを記述しました。
<script setup>
const { data } = await useAsyncData("blogQuery",()=>queryContent("/blog").find())
</script>
- useAsyncData、queryContentはNuxt Contentでデータを読み取るコード
- queryContentの括弧内に、contentフォルダ内の読み取りたいデータのパス(/blog)を記述
- queryContentに繋げてfind()とすることで、読み取りが行われる
- useAsyncData括弧内の「blogQuery」は自由に命名出来るが、他と重複しない名前を使う必要がある
記事を表示する
以上の設定で、contentフォルダの中のblogフォルダに作成したマークダウンデータが「data」定数内に保存されます。
<template>内に以下のように記述して出力します。
<template>
<div>
{{ data }}
</div>
</template>
この状態でNuxtを起動させると、以下のような画面が出力されます。
よく見ると先頭が大括弧で囲まれており、その中に波括弧で各ブログ記事が配列として読み込まれていることがわかります。
この配列データをv-forで分割していきます。
<template>
<div>
<div v-for="singleData in data" :key="singleData.id"></div>
//v-for="分割されたデータ in 分割したいデータ"
</div>
</template>
分割したいデータ=data(Nuxt Contentで読み取ったブログ記事)
分割されたデータ=singleData
分割されたデータは自由に名前を決めることが出来ます(単数形とわかるような命名にすることが多いです)
:keyは分割して表示するデータ(タグ)を識別するための記述で、ここでは<div>に該当します。
以上だけでは、データの出力ができません。出力のために{{ }}でsingleDataを出力します。
<template>
<div>
<div v-for="singleData in data" :key="singleData.id">
{{ singleData }}//追記
<hr> //追記
</div>
</div>
</template>
この状態でブラウザを確認すると、以下のようになります。
data内に保存されたブログ記事が、一つずつ区切られて出力されました!
記事データの中身を出力する
singleData(分割したデータ)の中身(title / dateなどの情報)を出力させるには、「.」で繋いで以下のように記述します。
<template>
<div>
<div v-for="singleData in data" :key="singleData.id">
{{ singleData.title }}
<br>
{{ singleData.date }}
<hr>
</div>
</div>
</template>
ブラウザを確認すると、マークダウンファイルのFrontmatter内に記述した title と date が出力されています!
画像と抜粋文を表示する
タイトルと日付が出力できたので、次は画像と抜粋文を指定しました。
画像の表示には通常の<img>タグではなく、自動で画像最適化を行ってくれるNuxt Imageの専用タグを使用します。
Nuxt Imageで使用する画像は public フォルダに保存しておく必要があります。
ルートディレクトリにpublicフォルダを作成、さらにその中へimagesフォルダを作成し、教材提供の画像データを配置しました。
Nuxt Imageとは
レスポンシブ対応や画像サイズ軽量化などの処理を自動で行ってくれるパッケージ。
様々な設定を追加することが可能で、一例としてwebp形式に画像を変換して表示したりできる。
Nuxt Imageのインストール
npm install -D @nuxt/image@rc
Nuxt Contentと同様に、Nuxt Imageを使用するために nuxt.config.ts へ設定の記述をします。
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
modules: [
"@nuxt/content",
"@nuxt/image"// Nuxt Imageの設定
],
})
Nuxt Imgaeの使い方
<nuxt-img :src="singleData.image" alt="blog-image" format="webp" />
基本は<img>タグを<nuxt-img>と置き換えるだけですが、教材内ではsrcの前に「:」を記述し、画像のパス名ではなくsingleDataの中のimageを取得しています。
これは各記事ごとに異なる画像を取得するための記述で、このように変動するデータは「ダイナミックデータ(動的なデータ)」と呼ばれます。
Vueで動的データを扱う際は、srcの前に「:」をつけます。
<template>
<div>
<div>
<h1>blog</h1>
<p>エンジニアの生活をお届けします</p>
<div v-for="singleData in data" :key="singleData.id">
<h3>{{ singleData.title }}</h3>
<p>{{ singleData.excerpt }}</p>
<p>{{ singleData.date }}</p>
<div>
<nuxt-img class="img" :src="singleData.image" alt="blog-image" format="webp" />
</div>
</div>
</div>
</div>
</template>
ブラウザを表示すると、上記のように出力されました。(CSSは見やすくするため独自で調整)
NuxtLinkとは
教材内では、blog.vueから記事へリンクさせるため、<NuxtLink>タグを使用されていました。
NuxtLinkは、Nuxt.jsで提供されるコンポーネントの1つで、ページ間の移動を簡単に実現できる専用リンクです。
各記事へ繋げるためのリンクを作成
:to=”singleData._path”として移動先のURLを指定します。
<NuxtLink :to="singleData._path">ReadMore</NuxtLink>
<a>タグと<NuxtLink>の使い分け
<a>は外部サイトへ移動するとき、<NuxtLink>はサイト内の別のページへ移動するためのリンクとして使用します。
記事の表示順序を整列
<script setup>
const { data } = await useAsyncData("blogQuery", () => queryContent("/blog").sort({ id: -1 }).find())
</script>
queryContent()に.sort({ id: -1 })と追加することで、日付の新しい記事が先頭に来るように整列できました。
まとめ・感想
- NuxtContentはcontentフォルダ内のデータを自動で読み取ってくれる仕組みを持つパッケージ
- NuxtContentを使用すると、各ブログ記事を配列としてデータ取得することができる
- 各記事データはマークダウン形式で作成
- Nuxt Imageを使用すると、webp形式で画像を出力してくれたり様々な設定ができる
- NuxtImageで使用する画像はpublicフォルダへ保存する
- 各記事へリンクさせるためにはNuxtLinkを使用する
- vueで動的データを扱う際は、属性名の前に「:」をつける(:src や :to など)
今までマークダウン形式でたくさんブログやnotionなどのメモアプリを記述してきましたが、マークダウンファイルを触ったのは初めてだったため、感動しました。
各データの出力方法や、NuxtContent、NuxtImageといったパッケージについても学ぶことができました。
各パッケージを使用してデータを参照するときは、ある決まったフォルダを参照する形式が多いのかな、という印象をなんとなくですが感じました。
次回は記事の詳細ページ作成に入ります。
本日は以上です!!