学习《了不起的盖茨比》的语言 – 第四天
你好!
上一次我们创建了一个文章列表页面。
第一天在这里。
本次我们希望创建一个链接文章列表页面与每个单独文章的连接。
制作一个蛞蝓
连接的关键词是明确的,即”slug”。
“slug”是用于区分每篇文章的ID。
在这里,我们可以将 slug(即文章文件名)设置为可理解的方式。
(因为文章文件是用 Markdown 来编写的,所以扩展名为 .md)。
让我们在GraphQL Playground中尝试执行以下操作。
query {
allMarkdownRemark {
edges {
node {
internal {
type
}
fileAbsolutePath
}
}
}
}
然后在右侧会显示 “MarkdownRemark” 类型以及其绝对路径(fileAbsolutePath)。
因此, 要获取slug,就需要获取文章文件名,在这种情况下,只需要提取绝对路径的最后部分并去掉扩展名就可以了。让我们来试一试。与页面相关的设置将会写在一个叫做gatsby-node.js的文件中。幸运的是,有一个非常简单的方法可用!那就是path.basename()。参考网站
const path = require('path')
module.exports.onCreateNode = ({ node , actions }) => {
const { createNodeField } = actions
if (node.internal.type === 'MarkdownRemark') {
const slug = path.basename(node.fileAbsolutePath , '.md' )
createNodeField({
node,
name: 'slug',
value: slug
})
}
}
我们可以重新启动开发服务器,并使用 GraphQL 来确认 slug 是否确实已经生成。
query {
allMarkdownRemark {
edges {
node {
fields{
slug
}
}
}
}
}
按下执行按钮后,文章文件名会作为“slug”显示出来。利用这个“slug”,我们可以创建一个新页面!
创建页面
如果要创建一个新页面,只需在pages文件夹中创建一个文件,然后使用该文件名作为路径即可创建页面。然而,如果有成千上万篇文章的话,采用这种方法会很痛苦。
因此,Gatsby 会创建一个名为 templates 的文件夹,在那里创建文章模板,并通过将之前创建的 slug 和文章数据相关联,只需创建一个模板就可以显示任意数量的文章。让我们试试看吧。
在 src 文件夹中创建一个名为 templates 的文件夹,并添加 blog-template.js 文件。
让我们具体使用 GraphQL 将 slug 与相应的内容进行关联。
除了以下查询之外,
query ( $slug: String! ) {
markdownRemark (fields: { slug: { eq: $slug } }) {
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
}
html
}
}
当在GraphQL画面的左下角的QUERY VARIABLES中添加以下内容时,
{
"slug": "how"
}
可以提取由slug确定的文章数据。重点在于这个部分。
(fields: { slug: { eq: $slug } })
eq表示等于,slug表示变量。由于在QUERY VARIABLES中指定了“how”,因此通过更改这里的变量,可以检索所需文章的数据。
让我们在所有的slug上都尝试一下这个。
设置是在gatsby-node.js文件中完成。
module.exports.createPages = async ({ graphql , actions }) => {
const { createPage } = actions
const blogTemplate = path.resolve('./src/templates/blog-template.js')
const res = await graphql(`
query {
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`)
res.data.allMarkdownRemark.edges.forEach( ({ node }) => {
createPage({
component: blogTemplate ,
path: `/bloglist/${node.fields.slug}` ,
context: {
slug: node.fields.slug
}
})
})
}
如果要按顺序解释它正在做的事情,那就是
首先,将查询数据存储在res中,并使用forEach方法对每篇文章进行createpage函数的调用,设置component(使用哪个模板?)、path(路径是什么?)和context(在这里定义的slug与之前在GraphQL页面左下方的QUERY VARIABLES中定义的slug具有相同的含义)。
换句话说,预先为每篇文章定义了一个slug,并根据指定的路径和slug之间的映射关系,将提取的数据显示在指定的模板中。
我现在想要在blog-template.js中使用查询,通过与“slug”的对应得出的数据,并将其显示出来。
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../Layouts/common'
export const query = graphql`
query ( $slug: String! ) {
markdownRemark (fields: { slug: { eq: $slug } }) {
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
}
html
}
}
`
const Blog = (props) => {
return (
<Layout>
<h1>{props.data.markdownRemark.frontmatter.title}</h1>
<p>{props.data.markdownRemark.frontmatter.date}</p>
<div dangerouslySetInnerHTML={{ __html: props.data.markdownRemark.html}}></div>
</Layout>
)
}
export default Blog
涉及到与”slug”的匹配。
(fields: { slug: { eq: $slug } })
没错!现在只需指定这个路径,就可以跳转到那篇文章了!
创建页面函数的好处在于,它不是在创建页面,而是改变了一张页面的信息,使其看起来像存在多个页面一样。这种思想以后还会再次出现。
好的,让我们在bloglist页面上添加一个链接吧!
从文章目录页面查看文章
import React from 'react'
import { Link , graphql , useStaticQuery } from 'gatsby'
import Layout from '../Layouts/common'
const BlogList = () => {
const data = useStaticQuery(graphql`
query {
allMarkdownRemark {
edges {
node {
frontmatter {
title
date (formatString: "MMMM DD, YYYY")
}
excerpt
fields{
slug
}
}
}
}
}
`)
return (
<Layout>
<h1>This is BlogList </h1>
<ol>
{data.allMarkdownRemark.edges.map( ({node}) => {
return (
<li key={node.fields.slug}>
<Link to={`/bloglist/${node.fields.slug}`} >
<h2>{node.frontmatter.title}</h2>
<p>{node.frontmatter.date}</p>
</Link>
</li>
)
})}
</ol>
</Layout>
)
}
export default BlogList
现在您可以从文章列表页面查看每篇文章啦!!
请在header.module.scss文件中添加以下内容,以防止布局因滚动而破坏。
body {
overflow-y: scroll;
}
这里基本上是教程的基础部分!
下次,我想学习标签功能和博客列表页面分割等内容。
如有任何错别字、遗漏字或代码错误,请留下评论,谢谢。
非常感谢阅读至此。