Gatsby是目前非常流行的静态页面生成框架。 页面生成是其最核心功能之一。 下面就来说说如何在Gatsby中自动生成文章页面,Category分类页面,以及tags标签页面。
Source: Gatsby官网
配置
gatsby-config.js中的配置
首先需要声明对markdown文件的监测,这样gatsby才能获取markdown中的frontmatter信息,比如slug:
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts`
}
}
动态生成页面文件
gatsby-node.js
接下来就可以在gatsby-node.js中通过graphql来获取所有markdown的元数据,也就是frontmatter信息:
const { data } = await graphql(`
query posts {
allMarkdownRemark {
nodes {
frontmatter {
slug
category
tag
}
}
}
}
`)
通过上面的graphql,就可以获取最为重要的信息,比如slug,这样我们就知道将要生成的文件名了。
接下来就可以调用actions.createPage来创建页面了:
data.allMarkdownRemark.nodes.forEach(node => {
actions.createPage({
path: `/posts/${node.frontmatter.slug}`,
component: path.resolve('./src/templates/post.js'),
context: { slug: node.frontmatter.slug }
})
})
这里需要的模板文件: ./src/templates/post.js
首先需要通过传递过来的slug查询相应页面:
export const query = graphql`
query PageDetails($slug: String) {
markdownRemark(frontmatter: {slug: {eq: $slug}}) {
html
frontmatter {
category
tag
title
thumbnail {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
接下来就可以生成页面了:
import React from "react"
import { graphql } from 'gatsby'
import Img from "gatsby-image"
import Layout from "../components/Layout"
import '../styles/post.css'
const Post = ({data}) => {
const { html } = data.markdownRemark
const { title, category, tag, thumbnail } = data.markdownRemark.frontmatter
return (
<Layout>
<div>
<h2>{title}</h2>
<p>类别: {category}</p>
<p>标签: {tag}</p>
<div>
</div>
<div dangerouslySetInnerHTML={{__html: html}} />
</div>
</Layout>
)
}
export default Post
这时重新启动gatsby,就可以访问页面了: /posts/xxxxxx 。 如果运行gatasby build就可以看到在public目录中新生成的页面。
生成自定义的category/ tag页面
在很多博客站点中,都提供针对某一个category / tag的页面,这样可以把同类的文章汇总到一起。
首先还是在gatsby-node.js中的预处理:
categories = new Set()
tags = new Set()
data.allMarkdownRemark.nodes.forEach(node => {
actions.createPage({
path: `/${node.frontmatter.category}/${node.frontmatter.slug}`,
component: path.resolve('./src/templates/details.js'),
context: { slug: node.frontmatter.slug }
})
categories.add(node.frontmatter.category);
node.frontmatter.tag.forEach(t => {
tags.add(t);
})
})
categories.forEach(category => {
actions.createPage({
path: `/categories/${category}`,
component: path.resolve('./src/templates/category.js'),
context: { category: category }
})
})
tags.forEach(tag => {
actions.createPage({
path: `/tags/${tag}`,
component: path.resolve('./src/templates/tag.js'),
context: { tag: tag }
})
})
接下来是在模板文件src/templates/tag.js中的处理:
import React from "react"
import { graphql, Link } from 'gatsby'
import Img from "gatsby-image"
const Tag = ({pageContext, data}) => {
const { tag } = pageContext;
const posts = data.posts.nodes;
return (
<>
<div>
<h3>标签:{tag}</h3>
<div>
{posts.map((post) => {
const {frontmatter} = post;
return(
<div key={post.id}>
<h3>
<Link to={`/${post.frontmatter.category}/${post.frontmatter.slug}`}>
{frontmatter.title}
</Link>
</h3>
<p>发布日期: {frontmatter.date.substring(0,10)}</p>
<p>类别:
<Link to={`/categories/${frontmatter.category}`}>
{frontmatter.category}
</Link>
</p>
<p>标签:{
frontmatter.tag.map(t => {
return (
<Link to={`/tags/${t}`}>
<span className="tag">{t}</span>
</Link>
)
})
}</p>
</div>
)
})}
</div>
</div>
</>
)
}
export default Tag
export const query = graphql`
query TagQuery($tag: String) {
posts: allMarkdownRemark(
filter: {frontmatter: {tag: {eq: $tag}}}
sort: {fields: frontmatter___date, order: DESC}
) {
nodes {
frontmatter {
title
slug
keywords
thumbnail {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
category
tag
date
}
id
}
}
}
`
category页面的实现类似。