学习《了不起的盖茨比》的语言 – 第四天

你好!

上一次我们创建了一个文章列表页面。

第一天在这里。

本次我们希望创建一个链接文章列表页面与每个单独文章的连接。

制作一个蛞蝓

连接的关键词是明确的,即”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;
  }

这里基本上是教程的基础部分!

下次,我想学习标签功能和博客列表页面分割等内容。

如有任何错别字、遗漏字或代码错误,请留下评论,谢谢。

非常感谢阅读至此。

广告
将在 10 秒后关闭
bannerAds