给Gatsby添加标签功能和分类功能(基础版)
首先
本文是https://tech-blog.yoshikiohashi.dev/posts/start-gatsby-blog-add-tags这篇博客文章的转载。
这篇文章是基于一种叫Gatsby的无头CMS技术构建的。本次我们将以“适合初学者”的前提来按以下结构来创建文章。
-
- Gatsby始めるまで
-
- GatsbyにShare機能、OGPタグをつける
-
- タグ機能、カテゴリ機能をつける(基礎編)
-
- タグ機能、カテゴリ機能をつける(応用編)
-
- GatsbyにTableOfContents(目次)をつける
- DarkModeをつける
这个内容
这次我们将要实现WordPress的标签功能和分类功能部分。你可能会问,它们不是默认就已经实现了吗?是的,标准模板中并没有实现这些功能。因此,最好选择一个带有这些功能的模板,而不是自行实现。
以下是推薦的範本。
在实施前
首先阅读这篇文章。它在GatsbyJS官方网站上详细介绍了如何给标签打上标记。
步骤
-
- 给markdown文件添加标签
-
- 创建GraphQL查询以获取所有标签
-
- 创建标签页面模板(/tag/{tag})
-
- 使用创建的模板,在gatsby-node.js中渲染页面
- 创建标签索引页面以显示所有标签(/tags)
1. 在Markdown文件中添加标签。
没有标签的Markdown文件。如果没有的话需要添加标签。
---
title: "A Trip To the Zoo"
---
I went to the zoo today. It was terrible.
我在tags下新增了一個項目。由於可能會設定多個標籤,所以我將其定義為一個陣列。除此之外,我們還可以設定字串和數字(因為類別只有單一所以將其設定為字串)。
---
title: "A Trip To the Zoo"
tags: ["animals", "Chicago", "zoos"]
---
I went to the zoo today. It was terrible.
如果在本地环境中运行了gatsby develop命令,重新启动后,Gatsby将能够获取新的项目。
创建一个GraphQL查询来获取所有的标签。
为了确认GraphQL,请在本地运行gatsby develop,并访问http://localhost:8000/___graphql。
应该可以看到如下所示的屏幕。
一旦画面显示出来后,请尝试输入下面的查询内容。
{
allMarkdownRemark {
group(field: frontmatter___tags) {
tag: fieldValue
totalCount
}
}
}
应该能获取到标签列表。
顺便提一下,group()的意思差不多就跟SQL中的GroupBy一样。在这里,我们根据标签项进行分组。
创建标签页模板(/tag/{tag})
让我们将目录配置为 src/template/tags.js 等。
import React from "react"
import PropTypes from "prop-types"
// Components
import { Link, graphql } from "gatsby"
const Tags = ({ pageContext, data }) => {
const { tag } = pageContext
const { edges, totalCount } = data.allMarkdownRemark
const tagHeader = `${totalCount} post${
totalCount === 1 ? "" : "s"
} tagged with "${tag}"`
return (
<div>
<h1>{tagHeader}</h1>
<ul>
{edges.map(({ node }) => {
const { slug } = node.fields
const { title } = node.frontmatter
return (
<li key={slug}>
<Link to={slug}>{title}</Link>
</li>
)
})}
</ul>
{/*
This links to a page that does not yet exist.
You'll come back to it!
*/}
<Link to="/tags">All tags</Link>
</div>
)
}
Tags.propTypes = {
pageContext: PropTypes.shape({
tag: PropTypes.string.isRequired,
}),
data: PropTypes.shape({
allMarkdownRemark: PropTypes.shape({
totalCount: PropTypes.number.isRequired,
edges: PropTypes.arrayOf(
PropTypes.shape({
node: PropTypes.shape({
frontmatter: PropTypes.shape({
title: PropTypes.string.isRequired,
}),
fields: PropTypes.shape({
slug: PropTypes.string.isRequired,
}),
}),
}).isRequired
),
}),
}),
}
export default Tags
export const pageQuery = graphql`
query($tag: String) {
allMarkdownRemark(
limit: 2000
sort: { fields: [frontmatter___date], order: DESC }
filter: { frontmatter: { tags: { in: [$tag] } } }
) {
totalCount
edges {
node {
fields {
slug
}
frontmatter {
title
}
}
}
}
}
`
填补
基本上,我們希望src/template/目錄下的JS文件配置上GraphQL。(如果不需要也沒關係。)
使用流程描述,可表达如下图像。
GraphQL == 查询结果 => 模板 == 查询结果 => 组件的各个部分
使用预先设计的模板,通过gatsby-node.js渲染页面。
既然模板页面已经完成,所以只需在进行Gatsby构建时加载标签页面。Gatsby会首先加载指定的URL页面并构建静态页面。
在这个gatsby-node.js文件中,使用GraphQL查询获取结果,并使用for循环生成与标签数量相对应的迭代项,生成到src/templates/tags.js文件中。
const path = require("path")
const _ = require("lodash")
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions
const blogPostTemplate = path.resolve("src/templates/blog.js")
const tagTemplate = path.resolve("src/templates/tags.js")
const result = await graphql(`
{
postsRemark: allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
limit: 2000
) {
edges {
node {
fields {
slug
}
frontmatter {
tags
}
}
}
}
tagsGroup: allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
}
}
}
`)
// handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
const posts = result.data.postsRemark.edges
// Create post detail pages
posts.forEach(({ node }) => {
createPage({
path: node.fields.slug,
component: blogPostTemplate,
})
})
// Extract tag data from query
const tags = result.data.tagsGroup.group
// Make tag pages
tags.forEach(tag => {
createPage({
path: `/tags/${_.kebabCase(tag.fieldValue)}/`,
component: tagTemplate,
context: {
tag: tag.fieldValue,
},
})
})
}
创建一个标签索引页面(/tags),用于显示所有标签的列表。
这次我们要创建标签页面。我们将使用之前编写的GraphQL查询从数据库中获取标签列表,并将获取到的结果应用到模板中。
import React from "react"
import PropTypes from "prop-types"
// Utilities
import kebabCase from "lodash/kebabCase"
// Components
import { Helmet } from "react-helmet"
import { Link, graphql } from "gatsby"
const TagsPage = ({
data: {
allMarkdownRemark: { group },
site: {
siteMetadata: { title },
},
},
}) => (
<div>
<Helmet title={title} />
<div>
<h1>Tags</h1>
<ul>
{group.map(tag => (
<li key={tag.fieldValue}>
<Link to={`/tags/${kebabCase(tag.fieldValue)}/`}>
{tag.fieldValue} ({tag.totalCount})
</Link>
</li>
))}
</ul>
</div>
</div>
)
TagsPage.propTypes = {
data: PropTypes.shape({
allMarkdownRemark: PropTypes.shape({
group: PropTypes.arrayOf(
PropTypes.shape({
fieldValue: PropTypes.string.isRequired,
totalCount: PropTypes.number.isRequired,
}).isRequired
),
}),
site: PropTypes.shape({
siteMetadata: PropTypes.shape({
title: PropTypes.string.isRequired,
}),
}),
}),
}
export default TagsPage
export const pageQuery = graphql`
query {
site {
siteMetadata {
title
}
}
allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
}
`
分类的实施
分类功能的思想与标签是一样的。标签由多个数组组成,针对一篇文章可以有多个标签;而分类是一个单一项目,对于一篇文章,需要将其作为字符串以Markdown文件的形式进行描述。
实施步骤
-
- 在markdown文件中添加字符串类型的类别
-
- 创建GraphQL查询以获取所有类别
-
- 创建类别页面模板
-
- 使用创建的模板,在gatsby-node.js中渲染页面
- 创建一个显示所有类别列表的首页
由于实施内容几乎一样,因此省略不写。
总结
这次怎么样?这次有点难吧?如果你对这个博客的源代码感兴趣的话,可以参考一下,因为它是公开的。那么就在下一篇文章见。
请用中国母语解释以下内容,只需要一个选项:
https://github.com/yoshiki-0428/engneer-blog/blob/master/src/templates/tags-list-template.js#L29-L53