【Nuxt.js】Nuxt Contentを使って、ブログ機能を実装する – その①
目次
今回は、Nuxt Contentの使い方について紹介しようと思います。
Nuxt Contentとは、Markdownを使って簡単にNuxt.jsでブログのような機能を実装することができるといったものです。
本記事を見る前にまず、Nuxt.jsのプロジェクトディレクトリを作成しておいてください。
Nuxt.jsの導入については、下記記事で紹介しています。
【Vue + Nuxt.js】Nuxt.jsとは?〜環境構築まで
Nuxt Contentとは?
「Nuxt Content」とは、Nuxt.jsのモジュールの一つで、Markdownで書いたものを記事として生成することができるといったものです。
いわゆるブログのようなものをイメージしていただければ良いと思います。
ブログのように、記事一覧ページや記事詳細ページにMarkdownで書いた内容を出力する、といったようなものになります。
また、ホットリロードにも対応しているため、記事を書きながら常にページを確認することができます。
他にも目次の自動生成や全文検索、カテゴリー・タグ付け、ページネーションなどにも対応しているため、割と実用的な機能が充実しています。
筆者制作の下記ブログサイトもNuxt Contentを導入しています。
かいものの助
https://www.kaimononosuke.com/
下記、Nuxt Contentの公式サイトになります。詳しくはこちらをご覧ください。
Nuxt Content公式サイト
https://content.nuxtjs.org/
Nuxt Contentの使い方
Nuxt Contentの使い方をご紹介していきます。
なお、今回紹介するのは下記項目です。
- markdownの記事ファイルを用意
- 記事詳細ページの作成
- 記事一覧ページ(カテゴリー一覧)の作成
と、基本的な使い方のみご紹介します。
タグ付けや、目次設置、全文検索などの機能については、次回以降にご紹介します。
Nuxt Contentのインストール
まず、Nuxt Contentモジュールをインストールします。
ターミナル(コマンドプロンプト)からあらかじめ制作しておいたNuxt.jsのプロジェクトディレクトリに移動してください。
そこで下記コマンドを実行してNuxt Contentをインストールしてください。
//npmの場合
npm install @nuxt/content
//yarnの場合
yarn add @nuxt/content
これでインストールは完了です。
さらに、nuxt.config.jsonファイルを開いてください。
そして、下記のように追記してください。
//・・・省略
modules: [
"@nuxt/content" //追記
],
//・・・省略
これで、準備は完了です。
ディレクトリ構成
今回、Nuxt Contentで記事を作成するにあたってディレクトリ構成は下記でいきます。
content
└ post
├ post-1.md
├ post-2.md
└ post-3.md
pages
├ post
│ └ _slug.vue
├ category
│ └ slug
│ └ index.vue
└ index.vue
「content」ディレクトリ内の「post」の中に、マークダウンファイルを用意します。
ここに追加された記事が自動でページとして生成されます。
「page」ディレクトリの中に、記事詳細ページと記事一覧ページ(カテゴリー)のテンプレートファイルを制作します。
作成したマークダウンの内容について、このテンプレファイルにてページが自動生成されます。
また、トップページ(index.vue)には新着記事一覧を設置します。
markdownの記事ファイルの用意
ルートディレクトリ(「pages」フォルダと同じ階層)に「content」フォルダを作成してください。
そして、その中に「post」フォルダを作成して、さらにその中にpost-1.mdファイルを作成してください。
post-1.mdファイルに下記のように記述してください。
---
title: テスト投稿
description: 説明が入ります。説明が入ります。説明が入ります。説明が入ります。説明が入ります。
category: カテゴリー1
---
# h1 タイトル
## h2 タイトル
### h3 タイトル
#### h4 タイトル
**大文字テキスト**
_斜体テキスト_
テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
- リスト 1
- リスト 2
- リスト 3
1. 連番リスト 1
2. 連番リスト 2
3. 連番リスト 3
[リンクテキスト](https://hogehogehoge.com/)
| テーブル項目 1 | テーブル項目 2 | テーブル項目 3 |
| -------------- | -------------- | -------------- |
| テーブル内容 1 | テーブル内容 2 | テーブル内容 3 |
上の部分が記事の設定項目になります。
冒頭の設定部分ですが、ここでページの記事のフロントマター(YAML形式のブロック)を設定できます。
タイトルやディスクリプション、カテゴリーなどが設定できます。
フロントマターを設定した下の部分から記事内容をマークダウン記法で記述していくことができます。
マークダウン記法については、下記が網羅的にまとまっていたので、こちらをご参照ください。
Markdown記法 サンプル集
https://qiita.com/tbpgr/items/989c6badefff69377da7
カテゴリーの管理について
この後から記事詳細ページを作っていくのですが、その前に、記事につけるカテゴリーの管理に関するお話をしようと思います。
先ほど、markdownの記事ファイル内のフロントマター部分でカテゴリーを設定しましたが、先ほどの例のように直書きすることもできるのですが、これですと記事数が増え、カテゴリー数も増えた際に、カテゴリーの管理が大変になってしまいます。
ですので、カテゴリーに関しては、別で設定ファイルを用意して、そこに記述して一括で管理するのがいいです。
まず、ルートディレクトリにtaxonomy.jsファイルを作成してください。
このファイル内には下記を記述してください。
module.exports = {
category: [
{ text: "カテゴリー1", slug: "category1" },
{ text: "カテゴリー2", slug: "category2" },
{ text: "カテゴリー3", slug: "category3" }
]
}
これで設定ファイルの準備は完了です。
「text」にカテゴリー名を入れ、「slug」にカテゴリーのスラッグ名を入れます。
もし、カテゴリーが増えたら、複製して同じように記述するだけです。
先ほど作成したmarkdownの記事ファイルのフロントマターには、カテゴリースラッグ名の方を記述しましょう。
//・・・省略
category: category1
//・・・省略
記事詳細ページの作成
続いて、先ほど作成した記事ファイルをページ側に表示するための記事詳細ページを作成します。
記事詳細ページを作成する前に、ページ内に記事の投稿日と更新日を出力したいです。
ですが、取得した日付をフォーマットしたいので、それに必要なライブラリをインストールしましょう。
下記コマンドを実行してライブラリをインストールしてください。
//npmの場合
npm install @nuxtjs/dayjs
//yarnの場合
yarn add @nuxtjs/dayjs
インストールが完了したら、nuxt.config.jsonファイルに下記のように追記してください。
//・・・省略
modules: [
"@nuxt/content",
"@nuxtjs/dayjs" //追記
],
//・・・省略
これで準備万端です。
「pages」フォルダ内に「post」フォルダを作成して、その中に_slug.vueファイルを作成してください。
_slug.vueファイル内には下記のように記述してください。
<template>
<div class="container">
<h1>{{ post.title }}</h1>
<p>
投稿日:{{ $dayjs(post.createdAt).format("YYYY/MM/DD") }}<br />
更新日:{{ $dayjs(post.updatedAt).format("YYYY/MM/DD") }}
</p>
<p>カテゴリー:{{ getCatName(post.category) }}</p>
<nuxt-content :document="post" />
</div>
</template>
<script>
import Vue from "vue";
import taxonomy from "@/taxonomy";
export default Vue.extend({
async asyncData ({ $content, params }) {
const post = await $content(`post/${params.slug}`).fetch()
return { post }
},
data () {
return {
category: [...taxonomy.category]
}
},
methods: {
getCatName (cat) {
return this.category.find((v) => v.slug === cat).text;
}
}
})
</script>
<style scoped>
</style>
一つずつ見ていきましょう。
まず、スクリプト内を見ると、下記のようなコードがありますが、これは「content」>「post」フォルダ内にある記事データを「asyncData」で取得しています。
async asyncData ({ $content, params }) {
const post = await $content(`post/${params.slug}`).fetch()
return { post }
}
_slug.vueとしているため、「${params.slug}」には、$content
のスラッグ(ファイル名)が入ります。
ここで取得した記事情報は「<template>」内で使用することができます。
//記事タイトル出力
{{ post.title }}
//記事内容出力
<nuxt-content :document="post" />
記事の投稿日と更新日の出力は下記のように記述します。
先ほどインストールしたdayjsで好きなようにフォーマットしてください。
//投稿日の出力
{{ $dayjs(post.createdAt).format("YYYY/MM/DD") }}
//更新日の出力
{{ $dayjs(post.updatedAt).format("YYYY/MM/DD") }}
また、カテゴリーですが、今回はtaxonomy.jsファイル内で管理しているので、ここから値を取ってきて出力してあげる必要があるので、設定ファイルから取得したカテゴリー群を入れる配列と配列から対象のカテゴリーを取得する関数を用意します。
//カテゴリーを入れる配列
category: [...taxonomy.category]
//配列から対象のカテゴリーを取得する関数
getCatName (cat) {
return this.category.find((v) => v.slug === cat).text;
}
そして、出力したい箇所でこの関数を実行すれば良いです。
//関数の実行
{{ getCatName(post.category) }}
そしたらブラウザで「http://localhost:3000/post/post-1」にアクセスしてみてください。
下記のように記事の内容が表示されればOKです。
記事一覧ページの作成
続いて、記事の一覧ページを作りましょう。
ここでは、トップページに記事一覧を新着順に表示してみようと思います。
まず、一覧を表示したいので、記事をもう一つ作っておきます。
「content」フォルダ内の「post」内にpost-2.mdファイルを作っておいてください。
カテゴリーはtaxonomy.jsに用意しておいた「カテゴリー2」を設定してください。
記事が用意できたら、まず一覧表示する投稿カードの一覧の部分を使いまわしたいので、コンポーネント化しようと思います。
「components」フォルダ内にArticleList.vueを作成してください。
このファイルに下記のように記述してください。
<template>
<div class="post-wrap">
<div v-for="post of posts" :key="post.slug" class="post_card">
<nuxt-link :to="{ name: 'post-slug', params: { slug: post.slug } }">
<p>{{ post.title }}</p>
<p>{{ getCatName(post.category) }}</p>
<p>{{ $dayjs(post.updatedAt).format("YYYY/MM/DD") }}</p>
</nuxt-link>
</div>
</div>
</template>
<script>
import Vue from "vue";
import taxonomy from "@/taxonomy";
export default Vue.extend({
props: {
posts: {
type: Array,
required: true
}
},
data () {
return {
category: [...taxonomy.category],
}
},
methods: {
getCatName (cat) {
return this.category.find((v) => v.slug === cat).text;
}
}
});
</script>
<style>
.post-wrap {
display: flex;
flex-wrap: wrap;
}
.post_card {
background: #dcdcdc;
padding: 2%;
width: 23.5%;
margin-left: 2%;
}
.post_card:nth-child(4n + 1) {
margin-left: 0;
}
.post_card a {
text-decoration: none;
color: #000;
}
.post_card a > p:first-child {
font-weight: bold;
font-size: 18px;
}
</style>
上記のように、propsを使って、渡ってきた記事データを取得して、その記事を「v-for」でループして表示するようにしています。
データの出力は先ほどの記事詳細ページでやったことと同じです。
また、投稿カードには少しスタイルをつけてみました。
そしたら、次に「pages」フォルダ直下のindex.vueを開いて、下記のように記述してください。
<template>
<div class="container">
<ArticleList v-if="posts != 0" :posts="posts" />
</div>
</template>
<script>
export default {
name: 'IndexPage',
async asyncData ({ $content }) {
const posts = await $content("post")
.sortBy('createdAt', 'desc')
.limit(10)
.fetch()
return {
posts
}
},
}
</script>
「asyncData」で記事を取得していますが、今回は、色々と他にも設定をしています。
//記事を降順(新着順)で取得
.sortBy('createdAt', 'desc')
//最大10記事まで取得
.limit(10)
ちなみに、「.sortBy(‘createdAt’, ‘asc’)」にすると、昇順になります。
取得した記事群をコンポーネントの呼び出し時に渡しています。
実際にブラウザで確認してみましょう。
「http://localhost:3000/」にアクセスしてみてください。
下記のように、新着一覧が表示されていれば、OKです。
カテゴリー一覧ページの作成
最後に、カテゴリー一覧ページの作り方も紹介します。
まず、「pages」フォルダ内に「category」フォルダを作成してください。
その中に「_slug」フォルダを作り、さらにその中に index.vueを作成してください。
このファイルがカテゴリー一覧ページになります。
また、カテゴリー一覧のURLを「/category/{カテゴリースラッグ名}/」にするためにこのようなディレクトリ構成にしました。
index.vueに下記のように記述しましょう。
<template>
<div class="container">
<h1>{{ getCatName($route.params.slug) }}</h1>
<section>
<div class="row">
<ArticleList :posts="posts" />
</div>
</section>
</div>
</template>
<script>
import Vue from "vue";
import taxonomy from "@/taxonomy";
export default Vue.extend({
data () {
return {
category: [...taxonomy.category]
}
},
async asyncData ({ store, $content, params }) {
const posts = await $content("post")
.sortBy('createdAt', 'desc')
.where({ category: { $contains: params.slug } })
.fetch()
return {
posts,
}
},
methods: {
getCatName (cat) {
return this.category.find((v) => v.slug === cat).text;
},
}
})
</script>
まず、h1タグにカテゴリー名を表示するために、先ほどと同じように「getCatName」関数を用意して、taxonomy.jsから対象のカテゴリーを取得しています。
そして、h1タグ内で「getCatName」関数を実行しているのですが、引数に「$route.params.slug」を入れることで、パラメーターのスラッグ名を設定しています。
つまり、「/category/food/」にアクセスしたら「food」を引数で渡します。
先ほどの新着一覧と同じように「asyncData」で記事データを降順で取得するのですが、今回は特定のカテゴリーの記事に絞る必要があるので、下記の記述を追記しております。
.where({ category: { $contains: params.slug } })
「params.slug」で、パラメーターのスラッグ名を取得しています。
これで、カテゴリーを絞った記事群を取得することができました。
あとは新着一覧と同じように、「<ArticleList :posts=”posts” />」でカテゴリーを絞った記事一覧を表示します。
そしたら、ブラウザで「http://localhost:3000/category/category1」にアクセスしてみてください。
下記のように、カテゴリー「カテゴリー1」を設定した記事が表示されていたら、成功です。
最後に
いかがだったでしょうか。
今回は、Nuxt Contentでブログ機能を実装する方法をご紹介しました。
今回は、Nuxt Contentの基本的な機能だけを紹介しましたが、もっと実用的にするために、次回は、タグ付け機能・目次の自動生成・全文検索機能・ページャー機能などのやり方をご紹介します。
Nuxt.jsで作ったサイトなどにちょっとしたブログ機能を付けたい時や汎用的なサイト作りなどにとても便利なモジュールなので、是非使ってみてください。