"The first draft of anything is shit."
"The first draft of anything is shit."
本文通过实现草稿模式和上下篇来进一步了解 Gatsby 的 Node APIs。
草稿模式即可以将文章保存为草稿而不被渲染出来。方式是在 front matters 中设置一个 draft
布尔域,以此域作为渲染参考。
这里有一个地方需要注意,前面文章提过,Markdown 插件需要所有文章中都有 draft
域且都是布尔类型才会生成相应的 GraphQL 查询。如果是新的博客这个问题不大,如果是迁移过来的,有两个解决方式,第一个是手动写个脚本给文章都补上域,另一个是利用 Gatsby 的 Node APIs 在 fields
上生成特定域,鲁棒性更好些。
观察 Remark 插件生成的 GraphQL 类型,我们可以发现,front matters 都被放在 frontmatter
域中,而与之同级的有一个前面文章提到过的 fields
域,用来放自定义生成的数据。
Gatsby 在生成 GraphQL 节点时提供了钩子 onCreateNode
,我们利用这个钩子往 fields
中放自定义的数据。
编辑 /gatsby-node.js
,如果是用了 starter 的话这里很可能已经有其它的代码,已有的不需要动,添加我们需要的即可。
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
createNodeField({
node,
name: 'draft',
value: Boolean(node.frontmatter.draft)
})
}
}
如此 fields
中就保证了会有 draft
这个域了。
有了标记之后,在生成页面的地方我们就需要过滤草稿。
首先是普通的文章页面生成,这个是在 createPages
钩子中,如果你的博客只有文章用到 Markdown 的话,可以在 GraphQL 查询中直接过滤,否则我们用前面文章的方法,先取所有 Markdown 文件再根据渲染的模板来分别处理各种类型的文章。
注意我把模板域的名字换成了自己更习惯的 layout
,原来的 starter 中应该叫 templateKey
。修改其实也很简单,搜索所有文件替换关键字即可。
options
.filter(
(_, i) =>
!(
edges[i].node.frontmatter.layout === 'blog-post' &&
edges[i].node.fields.draft
)
)
.forEach(option => createPage(option))
我在主页中也列举了最近的几篇文章,这里也需要过滤草稿,可以直接在 GraphQL 中过滤。
query IndexQuery {
latestPosts: allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
filter: {
fields: { draft: { ne: true } }
frontmatter: { layout: { eq: "blog-post" } }
}
limit: 5
) {
edges {
node {
excerpt(pruneLength: 200)
id
fields {
slug
}
frontmatter {
title
description
layout
date(formatString: "MMMM DD, YYYY")
}
}
}
}
}
其它地方同理。
在文章页面中我们通常会加入上下篇来引导继续浏览。这里我们同样在 createPages
钩子中处理,但这回我们添加到 context
域中,这个域里的数据会作为 props 传到模板组件中。
在 createPage
生成文章页面前添加处理代码计算上下篇:
options
.filter(
(_, i) =>
edges[i].node.frontmatter.layout === 'blog-post' &&
!edges[i].node.fields.draft
)
.forEach((option, i, blogPostOptions) => {
option.context.prev =
i === 0
? null
: {
title: blogPostOptions[i - 1].title,
path: blogPostOptions[i - 1].path
}
option.context.next =
i === blogPostOptions.length - 1
? null
: {
title: blogPostOptions[i + 1].title,
path: blogPostOptions[i + 1].path
}
})
然后在文章的 /src/templates/blog-post.js
组件里,接收 pageContext
props,就可以使用上面传入的数据了。这是我的例子。
通过实现这几个功能我们了解了 Gatsby 页面生成的方式以及其 Node APIs 的基本使用。Gatsby 的功能远不止这些,官方文档写得非常详细,需要实现其它功能建议先去看看有无现有的例子。本系列到这里暂告一段落,谢谢你的阅读,希望能对你搭建 Gatsby 博客有所帮助。
评论没有加载,检查你的局域网
Cannot load comments. Check you network.