我用Gatsbyjs制作了一个类似WordPress风格的简易博客,并进行了学习

因为Gatsbyjs的教程非常易懂,对我的学习非常有帮助,
所以我为了不忘记教程内容,尝试着制作了一个接近WordPress默认模板的样式。

另外,我是Gatsbyjs和WordPress的初学者,请多指教。


我做的东西可以在GitHub Pages上查看↓

Screen Shot 2020-01-04 at 21.45.46.png

我编写的代码如下:

undefined

创建gatsby的模板

npx -p gatsby-cli gatsby new myblog https://github.com/gatsbyjs/gatsby-starter-hello-world
cd myblog
yarn develop

在本地主机的8000端口上显示

Screen Shot 2020-01-04 at 22.38.12.png

1. 设定整体的风格

body {
    font-family: Verdana, sans-serif;
    margin: 0 auto;
    width: 900px;
}

a {
    text-decoration: none;
}

在gatsby-browser.js中加载

import "./src/styles/global.css"

每当更改gatsby-browser.js等配置文件时,需要使用Ctrl+C关闭开发服务器,然后再次使用yarn develop命令重新启动才能使更改生效。

创建并共享头部、底部和侧边栏。

把 src/index.js 的内容修改为以下样式,并更改文件扩展名为 jsx。

import React from "react"
import Layout from "../components/Layout"

export default () => (
  <Layout page={"top"}>
    <div>Hello world!</div>
  </Layout>
)

为了更容易理解,可以创建另一个页面来统一化。

import React from "react"
import Layout from "../components/Layout"

export default () => (
  <Layout>
    <h1>サンプルページ</h1>
    <p>
      これはサンプルページです。同じ位置に固定され、(多くのテーマでは)
      サイトナビゲーションメニューに含まれる点がブログ投稿とは異なります。まずは、サイト訪問者に対して自分のことを説明する自己紹介ページを作成するのが一般的です。たとえば以下のようなものです。
    </p>
    <blockquote class="wp-block-quote">
      <p>
        はじめまして。昼間はバイク便のメッセンジャーとして働いていますが、俳優志望でもあります。これは僕のサイトです。ロサンゼルスに住み、ジャックという名前のかわいい犬を飼っています。好きなものはピニャコラーダ、そして通り雨に濡れること。
      </p>
    </blockquote>
  </Layout>
)

在网站上设置元数据,以便在标题中加载。

module.exports = {
  siteMetadata: {
    title: "ホゲホゲブログ",
    description: "ホゲホゲによるブログです",
  },
}

载入包含全部零件的文件。

import React from "react"
import Header from "./Header"
import Main from "./Main"
import Sidebar from "./Sidebar"
import Footer from "./Footer"

export default ({ page = "default", children }) => (
  <>
    <Header page={page} />
    <Main sidebar={<Sidebar />}>{children}</Main>
    <Footer />
  </>
)

使用GraphQL获取网站元数据的文件,显示头部。

import React from "react"
import { useStaticQuery, Link, graphql } from "gatsby"
import styles from "../styles/header.module.css"

export default ({ page }) => {
  const {
    site: {
      siteMetadata: { title, description },
    },
  } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
          }
        }
      }
    `
  )

  return (
    <header>
      {page === "top" && <div className={styles.headerImg}>&nbsp;</div>}
      <div className={styles.headerBox}>
        <h1>
          <Link to="/">{title}</Link>
        </h1>
        <p>{description}</p>
      </div>
    </header>
  )
}

显示侧边栏和主要内容的文件

import React from "react"
import styles from "../styles/main.module.css"

export default ({ children, sidebar }) => (
  <div className={styles.flex}>
    <div className={styles.mainLeft}>{children}</div>
    <div className={styles.mainRight}>{sidebar}</div>
  </div>
)

稍后进行侧边栏显示,包括“最近的文章”和“分类”。

import React from "react"
import { Link } from "gatsby"

export default () => {
  return (
    <>
      <div>
        <h3>固定ページ</h3>
        <ul>
          <li>
            <Link to="/sample-page/">サンプルページ</Link>
          </li>
        </ul>
      </div>

      <div>
        <h3>最近の投稿</h3>
        <ul></ul>
      </div>

      <div>
        <h3>カテゴリー</h3>
        <ul></ul>
      </div>
    </>
  )
}

显示页脚的文件

import React from "react"
import { Link } from "gatsby"

export default () => (
  <>
    <hr />
    <Link to="https://www.gatsbyjs.org/">Powered by Gatsbyjs</Link>
  </>
)

我已经完成了共通部分的创建。

fcD99uOlTM.gif

3. 在首页上展示博客列表

使用Markdown在博客文件夹中编写内容,并将其显示为列表。
Markdown的内容如下所示。

---
title: Hello World
date: "2017-08-21"
categories: []
---

Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。

Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。

Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。Hello World。

安装可以将本地文件数据传递给Gatsby的插件和处理Markdown的插件。

yarn add gatsby-source-filesystem gatsby-transformer-remark

设置使插件可用

module.exports = {
  siteMetadata: {
    title: "ホゲホゲブログ",
    description: "ホゲホゲによるブログです",
  },
  plugins: [
    {
      resolve: "gatsby-source-filesystem",
      options: {
        path: `${__dirname}/blog`,
        name: "blog",
      },
    },
    "gatsby-transformer-remark",
  ],
}

创建gatsby-node.js文件,并使用createNodeField设置slug。这样,就可以从GraphQL获取到slug。

const path = require("path")
const { createFilePath } = require("gatsby-source-filesystem")
exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === "MarkdownRemark") {
    const slug = createFilePath({ node, getNode, basePath: "pages" })
    createNodeField({
      node,
      name: "slug",
      value: slug,
    })
  }
}

↑详细的说明在教程的第6部分和第7部分附近。

    • https://www.gatsbyjs.org/tutorial/part-six/

 

    https://www.gatsbyjs.org/tutorial/part-seven/

我使用 GraphQL 按日期进行排序并检索所需数据。

import React from "react"
import { Link, graphql } from "gatsby"
import Layout from "../components/Layout"
import styles from "../styles/index.module.css"

export default ({
  data: {
    allMarkdownRemark: { totalCount, edges: blogs },
  },
}) => (
  <Layout page={"top"}>
    <strong>投稿 ( {totalCount} ) </strong>
    {blogs.map(
      ({
        node: {
          id,
          frontmatter: { title, date },
          fields: { slug },
          excerpt,
        },
      }) => (
        <div key={id} className={styles.box}>
          <div className={styles.date}>{date}</div>
          <h2 className={styles.title}>
            <Link to={slug}>{title}</Link>
          </h2>
          <p>{excerpt}</p>
        </div>
      )
    )}
  </Layout>
)

export const query = graphql`
  query {
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "YYYY年MM月DD日")
          }
          fields {
            slug
          }
          excerpt
        }
      }
    }
  }
`

目前可以在首页上显示博客列表,但由于还没创建详细展示页面,所以访问时会显示404错误。

wcBbnWmC0G.gif

创建博客详细页面

我会创建一个用于显示博客页面的模板。

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

export default ({
  data: {
    markdownRemark: {
      html,
      frontmatter: { title, categories },
    },
  },
}) => {
  return (
    <Layout>
      <h1>{title}</h1>
      <>
        <strong>カテゴリー : </strong>
        {categories.length ? categories.join(", ") : "なし"}
      </>
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </Layout>
  )
}

export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
        categories
      }
    }
  }
`

修改gatsby-node.js文件,以便创建博客页面。

const path = require("path")
const { createFilePath } = require("gatsby-source-filesystem")

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === "MarkdownRemark") {
    const slug = createFilePath({ node, getNode, basePath: "pages" })
    createNodeField({
      node,
      name: "slug",
      value: slug,
    })
  }
}

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const result = await graphql(`
    query {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve("./src/templates/blog-post.jsx"),
      context: {
        // GraphQLのクエリの $slug 変数に設定する値
        slug: node.fields.slug,
      },
    })
  })
}

我已经确认了博客页面。

Screen Shot 2020-01-05 at 0.10.52.png

5. 创建按类别分类的列表页面

参考链接:https://www.gatsbyjs.org/docs/adding-tags-and-categories-to-blog-posts/

在博客文章中添加标签和分类的方法可以参考上述链接。

我将创建一个与之前相同的模板。

import React from "react"
import { Link, graphql } from "gatsby"
import Layout from "../components/layout"

export default ({
  data: {
    allMarkdownRemark: { totalCount, edges: blogs },
  },
}) => {
  return (
    <Layout>
      {blogs.map(
        ({
          node: {
            id,
            html,
            frontmatter: { title },
            fields: { slug },
          },
        }) => (
          <div key={id}>
            <h2>
              <Link to={slug}>{title}</Link>
            </h2>
            <div dangerouslySetInnerHTML={{ __html: html }} />
            <hr />
          </div>
        )
      )}
    </Layout>
  )
}

export const pageQuery = graphql`
  query($category: String!) {
    allMarkdownRemark(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { categories: { in: [$category] } } }
    ) {
      totalCount
      edges {
        node {
          id
          html
          frontmatter {
            title
          }
          fields {
            slug
          }
        }
      }
    }
  }
`

和创建博客详细页面时一样,我们在gatsby-node.js中也要进行相关操作。

  const path = require("path")
  const { createFilePath } = require("gatsby-source-filesystem")
  exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions
    if (node.internal.type === "MarkdownRemark") {
      const slug = createFilePath({ node, getNode, basePath: "pages" })
      createNodeField({
        node,
        name: "slug",
        value: slug,
      })
    }
  }

  exports.createPages = async ({ graphql, actions }) => {
    const { createPage } = actions
    const result = await graphql(`
      query {
        allMarkdownRemark {
          edges {
            node {
              fields {
                slug
              }
            }
          }
        }
+       categoriesAllMarkdownRemark: allMarkdownRemark {
+         group(field: frontmatter___categories) {
+           category: fieldValue
+         }
+       }
      }
    `)
    result.data.allMarkdownRemark.edges.forEach(({ node }) => {
      createPage({
        path: node.fields.slug,
        component: path.resolve("./src/templates/blog-post.jsx"),
        context: {
          // GraphQLのクエリの $slug 変数に設定する値
          slug: node.fields.slug,
        },
      })
    })
+   result.data.categoriesAllMarkdownRemark.group.forEach(({ category }) => {
+     createPage({
+       path: `/category/${category}/`,
+       component: path.resolve("./src/templates/categories.jsx"),
+       context: {
+         // GraphQLのクエリの $category 変数に設定する値
+         category,
+       },
+     })
+   })
  }

目前在页面内还没有链接,但是你可以直接在网址栏输入http://localhost:8000/category/ブログ/,这样可以只显示与该分类相关的文章。

Screen Shot 2020-01-05 at 0.18.36.png

获取并显示侧边栏的信息。

将 Sidebar.jsx 更改为从 GraphQL 中获取数据

import React from "react"
import { useStaticQuery, Link, graphql } from "gatsby"

export default () => {
  const {
    recentlyAllMarkdownRemark: { edges: recentlyBlogs },
    categoriesAllMarkdownRemark: { group: categories },
  } = useStaticQuery(
    graphql`
      query {
        recentlyAllMarkdownRemark: allMarkdownRemark(
          sort: { fields: [frontmatter___date], order: DESC }
          limit: 5
        ) {
          edges {
            node {
              id
              frontmatter {
                title
              }
              fields {
                slug
              }
            }
          }
        }
        categoriesAllMarkdownRemark: allMarkdownRemark {
          group(field: frontmatter___categories) {
            category: fieldValue
            totalCount
          }
        }
      }
    `
  )

  return (
    <>
      <div>
        <h3>固定ページ</h3>
        <ul>
          <li>
            <Link to="/sample-page/">サンプルページ</Link>
          </li>
        </ul>
      </div>

      <div>
        <h3>最近の投稿</h3>
        <ul>
          {recentlyBlogs.map(
            ({
              node: {
                id,
                frontmatter: { title },
                fields: { slug },
              },
            }) => (
              <li key={id}>
                <Link to={slug}>{title}</Link>
              </li>
            )
          )}
        </ul>
      </div>

      <div>
        <h3>カテゴリー</h3>
        <ul>
          {categories.map(({ category, totalCount }) => (
            <li key={category}>
              <Link to={`category/${category}`}>{category}</Link> ( {totalCount}{" "}
              )
            </li>
          ))}
        </ul>
      </div>
    </>
  )
}

能够显示侧边栏

Screen Shot 2020-01-05 at 0.20.30.png

7. 网站元数据

参考链接:Gatsby教程的第八部分。

我会设置网站的meta标签、标题和描述。

因为要使用 react-helmet,所以需要安装。

yarn add gatsby-plugin-react-helmet react-helmet
  module.exports = {
    siteMetadata: {
      title: "ホゲホゲブログ",
      description: "ホゲホゲによるブログです",
    },
    plugins: [
      {
        resolve: "gatsby-source-filesystem",
        options: {
          path: `${__dirname}/blog`,
          name: "blog",
        },
      },
      "gatsby-transformer-remark",
+     "gatsby-plugin-react-helmet",
    ],
  }
  import React from "react"
+ import Helmet from "react-helmet"
  import { useStaticQuery, Link, graphql } from "gatsby"
  import styles from "../styles/header.module.css"

  export default ({ page }) => {
    const {
      site: {
        siteMetadata: { title, description },
      },
    } = useStaticQuery(
      graphql`
        query {
          site {
            siteMetadata {
              title
              description
            }
          }
        }
      `
    )

    return (
+     <>
+       <Helmet
+         htmlAttributes={{ lang: "ja" }}
+         title={title}
+         meta={[
+           {
+             name: "description",
+             content: description,
+           },
+         ]}
+       />
        <header>
          {page === "top" && <div className={styles.headerImg}>&nbsp;</div>}
          <div className={styles.headerBox}>
            <h1>
              <Link to="/">{title}</Link>
            </h1>
            <p>{description}</p>
          </div>
        </header>
+     </>
    )
  }

标题标签和meta标签可以进行设置。

Screen Shot 2020-01-05 at 0.32.47.png

非常感谢您一直阅读至最后。m(_ _)m