hene

hene.dev

特定のカテゴリーのブログを表示

特定のカテゴリーのブログを表示

VuePress のブログ一覧ページをいい感じに変更 - hene.dev では、ブログ一覧ページを作成しました。

今回のブログ一覧ページの変更では、特定のカテゴリーのブログを一覧表示できるようにしました。また、特定のカテゴリーのブログ一覧すべてのブログ一覧 ページは同じコンポーネントを使うようにしました。

変更したページ例

  • ブログ一覧ページ

カテゴリー ページから、Tag ページに変更しました。

ブログ一覧を表示するコンポーネント

まず、ブログ(すべてのブログ or 特定のカテゴリーのブログ)を表示するコンポーネントを変更しました。

BlogList.vue

ブログ(すべてのブログ or 特定のカテゴリーのブログ)を表示するコンポーネントです。

<!-- src/.vuepress/components/BlogList.vue -->

<template lang="pug">
  main.blog-list
    .content
      h1
        a.header-anchor(href="#blog" aria-hidden="true") #
        | {{ title }}
      .blog(v-for="post in posts")
        p.blog-date {{ date(post.frontmatter.date) }}
        h2.blog-title
          a(v-bind:href="post.path") {{ post.title }}
        .blog-categories
          a.blog-category(v-for="category in post.frontmatter.categories" :href="'../category/' + category + '.html'") {{ category }}
</template>

<script>
export default {
  computed: {
    isAllPosts() {
      return (
        this.$page.path === "/blog/" || typeof this.$category === "undefined"
      );
    },
    title() {
      return this.isAllPosts
        ? "Blog"
        : `Blog / ${this.$route.meta.categoryName}`;
    },
    categoryPosts() {
      return this.$category.posts
        .filter(post => post.regularPath.startsWith("/_posts/blog/"))
        .sort(
          (x, y) => new Date(y.frontmatter.date) - new Date(x.frontmatter.date)
        );
    },
    allPosts() {
      return this.$site.pages
        .filter(post => post.regularPath.startsWith("/_posts/blog/"))
        .sort(
          (x, y) => new Date(y.frontmatter.date) - new Date(x.frontmatter.date)
        );
    },
    posts() {
      return this.isAllPosts ? this.allPosts : this.categoryPosts;
    }
  },
  methods: {
    date(postDate) {
      const date = new Date(postDate);
      const yyyy = date.getFullYear();
      const MM = ("0" + (date.getMonth() + 1)).slice(-2);
      const dd = ("0" + date.getDate()).slice(-2);
      return [yyyy, MM, dd].join("/");
    }
  }
};
</script>

script

computedmethods の中で何をしているか詳しく説明します。

computed

isAllPosts()

以下 2 つを比較しています。

  • this.$page.path/blog/ かどうか比較しています。
  • this.$categoryundefined かどうか比較しています。
isAllPosts() {
  return (
    this.$page.path === "/blog/" || typeof this.$category === "undefined"
  );
},

他の方法

最初、isAllposts() を以下のように書いていました。

isAllPosts() {
  return this.$page.path === "/blog/";
},

npm run build すると、/category/ ページが残っていてエラーが出たので、 typeof this.$category === "undefined" を追加することで対応しました。

error Error rendering /category/: false
undefined
TypeError: Cannot read property 'posts' of undefined
    at a.categoryPosts (src/.vuepress/components/BlogList.vue:27:28)
    at a.categoryPosts (/Users/username/privateworkspace/hene/node_modules/vue/dist/vue.runtime.common.prod.js:6:29311)
    at a.posts (src/.vuepress/components/BlogList.vue:41:52)
    at a.posts (/Users/username/privateworkspace/hene/node_modules/vue/dist/vue.runtime.common.prod.js:6:29311)
    at a.render (src/.vuepress/components/BlogList.vue?f542:1:131)
    at a.t._render (/Users/username/privateworkspace/hene/node_modules/vue/dist/vue.runtime.common.prod.js:6:34886)
    at /Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:70219
    at Gi (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:66783)
    at ro (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:70195)
    at eo (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:69826)
    at bt.Qi [as renderNode] (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:67073)
    at bt.next (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:20498)
    at n (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:18710)
    at /Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:68184
    at Qi (/Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:68192)
    at /Users/username/privateworkspace/hene/node_modules/vue-server-renderer/build.prod.js:1:70293
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build: `vuepress build src`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/username/.npm/_logs/2019-05-25T06_26_27_609Z-debug.log

title()

isAllPosts を用いて、ブログ一覧ページとカテゴリーページで表示するタイトルを判別しています。

  • ブログ一覧ページ: Blog
  • カテゴリーページ: Blog / カテゴリー名
title() {
  return this.isAllPosts
    ? "Blog"
    : `Blog / ${this.$route.meta.categoryName}`;
},

categoryPosts()

カテゴリーページで表示するブログを取得して、日付を降順(新しい日付のものを上)にしています。

categoryPosts() {
  return this.$category.posts
    .filter(post => post.regularPath.startsWith("/_posts/blog/"))
    .sort(
      (x, y) => new Date(y.frontmatter.date) - new Date(x.frontmatter.date)
    );
},

allPosts()

すべてのブログを取得して、日付を降順(新しい日付のものを上)にしています。

allPosts() {
  return this.$site.pages
    .filter(post => post.regularPath.startsWith("/_posts/blog/"))
    .sort(
      (x, y) => new Date(y.frontmatter.date) - new Date(x.frontmatter.date)
    );
},

posts()

isAllPosts を用いて、すべてのブログを表示するかカテゴリーのページを表示するか判別しています。

posts() {
  return this.isAllPosts ? this.allPosts : this.categoryPosts;
}

methods

date(postDate)

日付を 2019/05/25 のような形式に変換しています。

date(postDate) {
  const date = new Date(postDate);
  const yyyy = date.getFullYear();
  const MM = ("0" + (date.getMonth() + 1)).slice(-2);
  const dd = ("0" + date.getDate()).slice(-2);
  return [yyyy, MM, dd].join("/");
}

Markdown ファイルの内容を表示

Content には、Markdown ファイルの内容が表示されます。

v-ifv-else-if の条件すべてに当てはまらなかったときは、BlogBlogListLog のコンポーネントを表示せずに Markdown ファイルの内容が表示されます。

今回表示したい BlogList(すべてのブログ or 特定のカテゴリーのブログ を表示するコンポーネント)は、以下のとき表示するようにしました。

  • すべてのブログを表示: $page.regularPath/_posts/blog/ で始まるとき
  • 特定のカテゴリーのブログを表示: $page.path/blog/ のとき

CustomContent.vue

<!-- src/.vuepress/components/CustomContent.vue -->

<template lang="pug">
div
  Blog(v-if="$page.regularPath.startsWith('/_posts/blog/')")
  BlogList(v-else-if="$page.regularPath.startsWith('/category/') || $page.path === '/blog/'")
  Log(v-else-if="$page.regularPath.startsWith('/_posts/log/')")
  Content(v-else)
</template>

CustomContent を経由するように変更

通常のページは Markdown ファイルの内容を Page -> Content のように経由して表示しています。

そこで、Page -> CustomContent -> Content のように経由して表示するように変更しました。

Page.vue

 <!-- src/.vuepress/theme/components/Page.vue -->

 <template lang="pug">
   main.page
     slot(name="top")

-    Content
+    CustomContent

     略

ブログ一覧ページの設定

すべてのブログを表示するときの設定です。

src/.vuepress/components/CustomContent.vue で指定した、 this.$page.path/blog/ のときにこのページが表示されます。

設定内容

  • サイドバー: 非表示
  • タイトル: blog
  • 説明: ブログ一覧
  • パーマリンク: /blog

blog.md

<!-- src/pages/blog.md -->

---

sidebar: false
title: Blog
description: ブログ一覧
permalink: /blog

---

できなかったこと

カテゴリー一覧ページのサイドバーを非表示にしたかったのですが、わかりませんでした・・

参考

関連記事