尽管Gatsby的表现令人惊叹,但最好不要强迫用户将每一篇帖子都加载到同一页面上。取而代之的是,我们将探索gatsby-awesome-pagination插件来将我们的帖子归档分割成更易于管理的部分。
安装
我们将从gatsby-starter-blogStarter开始,因为它带有降价支持。
1$ gatsby new pagination-example https://github.com/gatsbyjs/gatsby-starter-blog
2$ yarn add gatsby-awesome-pagination
分页
在我们的gatsby-node.js
文件中,让我们导入paginate
方法,并在我们的帖子查询下面向它传递一个对象。它只需要几件事,即createPage
操作、我们的帖子数组、每页的项目限制、我们新归档页面的插件和它的模板。现在,当我们进行这个查询时,我们将在`pageContext‘道具中获得一堆额外的东西,我们将使用它来管理呈现哪个页面。
1[label gatsby-node.js]
2const { paginate } = require('gatsby-awesome-pagination');
3
4exports.createPages = async ({ graphql, actions }) => {
5 const { createPage } = actions
6
7 const blogPost = path.resolve(`./src/templates/blog-post.js`)
8 const result = await graphql(` ... `)
9
10 paginate({
11 createPage,
12 items: result.data.allMarkdownRemark.edges,
13 itemsPerPage: 3,
14 pathPrefix: '/posts',
15 component: path.resolve('src/templates/blog-archive.js')
16 });
17};
模板
据我所知,‘gatsby-awawed-pagination’插件只是用来对单独的‘存档’页面进行分页。因此,我们将链接到一个包含所有内容的单独的帖子页面,而不是向初学者的主页添加分页。普通页面上的帖子组可能最好只使用静态查询,并使用类似旋转木马的东西来管理显示的内容。
1[label index.js]
2import React from "react";
3import { Link, graphql } from "gatsby";
4import Bio from "../components/bio";
5import Layout from "../components/layout";
6
7class BlogIndex extends React.Component {
8 render() {
9 const { data } = this.props;
10
11 return (
12 <Layout location={this.props.location}>
13 <Bio />
14 <Link to='/posts'><button>See All Posts</button></Link>
15 </Layout>
16 )
17 }
18};
19
20export default BlogIndex;
我们的存档模板已经可以访问我们的查询的pageContext
在它的props中,我们将把它传递给一个单独的Pager
组件。请注意,我们需要使用普通查询而不是静态查询,因为我们的pageContext
将向skip
和limit
参数传递值,我们也需要设置这些参数。
1[label blog-archive.js]
2import Pager from '../components/pager';
3
4export const pageQuery = graphql`
5 query($skip: Int!, $limit: Int!) {
6 site { ... }
7 allMarkdownRemark(
8 sort: { fields: [frontmatter___date], order: DESC},
9 skip: $skip,
10 limit: $limit
11 ) {
12 edges { ... }
13 }
14 }
15`;
16
17const BlogArchive = ({ data, pageContext, location }) => {
18 const posts = data.allMarkdownRemark.edges;
19
20 return (
21 <Layout location={location}>
22 {posts.map(({ node }) => {
23 const title = node.frontmatter.title || node.fields.slug
24 return (
25 <article key={node.fields.slug}>
26 <header>
27 <h3>
28 <Link to={node.fields.slug}> {title} </Link>
29 </h3>
30 <small>{node.frontmatter.date}</small>
31 </header>
32 <section>
33 <p dangerouslySetInnerHTML={{ __html: node.frontmatter.description || node.excerpt }} />
34 </section>
35 </article>
36 )
37 })}
38
39 <Pager pageContext={pageContext} />
40 </Layout>
41 )
42};
43
44export default BlogArchive;
寻呼机
最后一步非常简单,只需从pageConext
获取页面路径。如果您记录pageConext
,您可以看到传递给查询的skip
和limit
属性,以及您可以用来为每个页面生成数字和链接的pageNumber
和number OfPages
。
1[label components/pager.js]
2import React from 'react';
3import { Link } from 'gatsby';
4
5const Pager = ({ pageContext }) => {
6 console.log(pageContext);
7 const { previousPagePath, nextPagePath } = pageContext;
8 return (
9 <nav style={{ display: 'flex', justifyContent: 'space-between' }}>
10 <div>
11 {previousPagePath && (
12 <Link to={previousPagePath}>
13 <button>← Newer Posts</button>
14 </Link>
15 )}
16 </div>
17
18 <div style={{ justifySelf: 'flex-end' }}>
19 {nextPagePath && (
20 <Link to={nextPagePath}>
21 <button>Older Posts →</button>
22 </Link>
23 )}
24 </div>
25 </nav>
26 );
27};
28
29export default Pager;
帖子
在每个帖子之间添加导航同样简单,甚至不需要插件。这个特定的启动器实际上已经支持这一点,但让我们暂时假装它不支持。
在我们从查询创建页面的地方,我们只需要添加两个字段,然后就可以在pageConext
中访问它们。如果这是第一篇帖子,则不应该存在preved‘,否则我们将返回最后一篇帖子。与
next`相同,如果存在下一个帖子,则只返回下一个帖子。
1[label gatsby-node.js]
2posts.forEach((post, index) => {
3 createPage({
4 path: post.node.fields.slug,
5 component: blogPost,
6 context: {
7 slug: post.node.fields.slug,
8 prev: index === 0 ? null : posts[index - 1].node,
9 next: index === (posts.length - 1) ? null : posts[index + 1].node
10 },
11 })
12});
这是与我们的Pager
相同的执行,检查是否存在prev/Next,抛出一个Link
,就完成了。
1[label blog-post.js]
2const BlogPostTemplate = ({ data, pageContext, location }) => {
3 const post = data.markdownRemark;
4 const { prev, next } = pageContext;
5
6 return (
7 <Layout location={location}>
8 <Link to='/posts'>Archive</Link>
9 <article>
10 <header>
11 <h1> {post.frontmatter.title} </h1>
12 <p> {post.frontmatter.date} </p>
13 </header>
14 <section dangerouslySetInnerHTML={{ __html: post.html }} />
15 <hr />
16 </article>
17
18 <nav style={{ display: 'flex', justifyContent: 'space-between' }}>
19 <div>
20 {prev && <Link to={prev.fields.slug} rel="prev"> ← Last Post </Link>}
21 </div>
22
23 <div style={{ justifySelf: 'flex-end' }}>
24 {next && <Link to={next.fields.slug} rel="next"> Next Post → </Link>}
25 </div>
26 </nav>
27 </Layout>
28 )
29};
30
31export default BlogPostTemplate;
结束语
这个插件仍在完善中,但我很兴奋地看到他们将如何改进这个已经令人难以置信的简单设计。