# カテゴリー一覧を表示するVue.jsアプリの作成
2024-02-11 14:04:00
VuePressで書いた記事を、カテゴリーごとに一覧表示したかった。 enhanceApp.jsでMarkdownのfrontmatterからカテゴリーを集め、Category.vueでカテゴリーごとに記事を並べる。
# enhanceApp.jsで全ページのカテゴリーを集める
VuePressのenhanceApp.jsで、Markdownファイルからカテゴリーを取得する。 Vueのmixinを使い、全てのページで共通の処理として定義する。
export default ({ Vue }) => {
Vue.mixin({
computed: {
categories() {
const categories = new Set();
this.$site.pages.forEach(page => {
if (page.frontmatter.category) {
categories.add(page.frontmatter.category);
}
});
return Array.from(categories);
}
}
});
};
このコードは、全てのページのfrontmatterから category を取り出す。
Set に入れることで、重複のないカテゴリー一覧を作っている。
# Category.vueでカテゴリーごとに記事を並べる
カテゴリーごとに記事一覧を表示するVueコンポーネントを、Category.vueとして作成する。
<template>
<div>
<div v-for="category in categories" :key="category">
<h3>{{ category }} の記事一覧</h3>
<ul>
<li v-for="post in filteredPosts(category)" :key="post.title">
<!-- post.title が存在する場合のみ表示 -->
<router-link v-if="post.frontmatter.title" :to="post.path">{{ post.frontmatter.title }}</router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
categories: [],
};
},
computed: {
filteredPosts() {
return (category) => {
if (!this.$site || !this.$site.pages) {
return [];
}
return this.$site.pages
.filter(page => page.frontmatter.category === category && page.frontmatter.title)
.sort((a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date));
};
},
},
created() {
this.categories = this.$store.state.categories;
}
};
</script>
filteredPosts は、カテゴリーが一致し、タイトルがある記事だけを返す。
記事は date の新しい順に並べている。
カテゴリーは created フック内でVuexストアから取得している。
# カテゴリーをCategory.vue内に直接書く場合
カテゴリーを固定で定義したい場合は、data に直接書く。
<template>
<div>
<div v-for="category in categories" :key="category">
<h3>{{ category }} の記事一覧</h3>
<ul>
<li v-for="post in filteredPosts(category)" :key="post.title">
<!-- post.title が存在する場合のみ表示 -->
<router-link v-if="post.frontmatter.title" :to="post.path">{{ post.frontmatter.title }}</router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
categories: ["Vue.js", "React", "Angular"], // カテゴリーを直接定義
};
},
computed: {
filteredPosts() {
return (category) => {
if (!this.$site || !this.$site.pages) {
return [];
}
return this.$site.pages
.filter(page => page.frontmatter.category === category && page.frontmatter.title)
.sort((a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date));
};
},
},
};
</script>
この例では ["Vue.js", "React", "Angular"] を定義している。
created フックでストアから取得する処理は不要になる。