由于我现在的博客文章比较多了,而我基于 Gatsby 的博客又只有文章页和索引页两个页面,这样索引页看起来就特别长,这就有了分页的需求。本文主要学习这篇文章得来,gatsby-paginated-blog也是基于gatsby-starter-blog的。
关于 Gatsby
这次添加分页读了一下官方的教程, 对 Gatsby 多了一些理解:
Gatsby 的数据是存在 graphql 里的,而数据是插件处理生成的,比如最重要的两个插件:
gatsby-source-filesystem
在 graphql 里新增了allFile
和file
两个 objectgatsby-transformer-remark
新增了allMarkdownRemark
和markdownRemark
两个 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
创建所有的索引页。