xdays

Gatsby添加分页

August 11, 2019

由于我现在的博客文章比较多了,而我基于 Gatsby 的博客又只有文章页和索引页两个页面,这样索引页看起来就特别长,这就有了分页的需求。本文主要学习这篇文章得来,gatsby-paginated-blog也是基于gatsby-starter-blog的。

关于 Gatsby

这次添加分页读了一下官方的教程, 对 Gatsby 多了一些理解:

Gatsby 的数据是存在 graphql 里的,而数据是插件处理生成的,比如最重要的两个插件:

  1. gatsby-source-filesystem在 graphql 里新增了allFilefile两个 object
  2. gatsby-transformer-remark新增了allMarkdownRemarkmarkdownRemark两个 object

Gatsby 不区分 page 和 post,内部都称为 page,所以在gatsby-node.js里只有createPage这个接口。那如果要对博客索引分页就要模板化src/pages/index.js这个页面。

添加分页

所有的改动都在这次 commit里了

模板化索引页

首先将博客索引页重命名并挪到 templates 目录下:

mv src/pages/index.js src/templates/blog-list.js

修改 graphql 查询,添加 skip 和 limit 两个参数,来获取特定页面里的内容。

export const pageQuery = graphql`
  query blogPageQuery($skip: Int!, $limit: Int!) {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(
      sort: { fields: [frontmatter___date], order: DESC }
      limit: $limit
      skip: $skip
    ) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            title
          }
        }
      }
    }
  }
`

渲染索引页的时候还需要知道总共有多少页以及当年在第几页,这些都是作为 pros 传递给索引页的组件的。

const { currentPage, numPages } = this.props.pageContext
const isFirst = currentPage === 1
const isLast = currentPage === numPages
const prevPage = currentPage - 1 === 1 ? '/' : (currentPage - 1).toString()
const nextPage = (currentPage + 1).toString()

然后上一步初始化的几个变脸主要供分页导航里的逻辑使用的。

<ul
  style={{
    display: 'flex',
    flexWrap: 'wrap',
    justifyContent: 'space-between',
    alignItems: 'center',
    listStyle: 'none',
    padding: 0,
  }}
>
  {!isFirst && (
    <Link to={prevPage} rel="prev">
      ← Previous Page
    </Link>
  )}
  {Array.from({ length: numPages }, (_, i) => (
    <li
      key={`pagination-number${i + 1}`}
      style={{
        margin: 0,
      }}
    >
      <Link
        to={`/${i === 0 ? '' : i + 1}`}
        style={{
          padding: rhythm(1 / 4),
          textDecoration: 'none',
          color: i + 1 === currentPage ? '#ffffff' : '',
          background: i + 1 === currentPage ? '#007acc' : '',
        }}
      >
        {i + 1}
      </Link>
    </li>
  ))}
  {!isLast && (
    <Link to={nextPage} rel="next">
      Next Page →
    </Link>
  )}
</ul>

至此索引页模板化完成。

创建博客索引页

刚才说了所有的页面都是通过createPage这个接口创建,所以我们在gatsby-node.js里添加创建博客索引页页面的代码,然后通过 context 给组件传递对应的 props 就可以了

// Create blog post list pages
const postsPerPage = 20
const numPages = Math.ceil(posts.length / postsPerPage)

Array.from({ length: numPages }).forEach((_, i) => {
  createPage({
    path: i === 0 ? `/` : `/${i + 1}`,
    component: path.resolve('./src/templates/blog-list.js'),
    context: {
      limit: postsPerPage,
      skip: i * postsPerPage,
      numPages,
      currentPage: i + 1,
    },
  })
})

先计算出一共分多少页,然后通过forEach创建所有的索引页。