aafenguk

程序员,旅游爱好者。 个人网站:https://www.aafeng.uk

Gatsby中的页面生成

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页面的实现类似。

Like my work??
Don't forget to support or like, so I know you are with me..

CC BY-NC-ND 2.0

Want to read more ?

Login with one click and join the most diverse creator community.