reactjs - Gatsby.js 中的多个模板

标签 reactjs graphql markdown gatsby

我对 Gatsby 还很陌生,希望拥有多个可用于不同页面的模板,例如 Landingpage、Contact 和 About 不能使用相同的模板。

我现在在 gatsby-node.js 中编写了一个丑陋的代码,但它只适用于两个模板,这是我的代码(顺便说一句,我从 markdownfiles 中获取数据):

Mardown 文件 1:

---
title: 'Index page'
slug: '/'
template: indexTemplate //This is where i declare which template it shall use
content: 'Index content'
---

Mardown 文件 2:

---
slug: '/my-first-post'
date: '2019-05-04'
title: 'My first blog post!'
content: 'Content post 1'
template: postTemplate
---

gatsby-node.js:

exports.createPages = async ({ actions, graphql, reporter }) => {
    const { createPage } = actions
  
    const result = await graphql(`
    query{
      allMarkdownRemark {
        nodes {
          frontmatter {
            slug
            template
          }
        }
      }
    }
  `)

  const postTemplate = require.resolve(`./src/templates/postTemplate.js`)
  const indexTemplate = require.resolve(`./src/templates/indexTemplate.js`)
  const aboutTemplate = require.resolve(`./src/templates/aboutTemplate.js`) // I also want a template for my aboutpage
  
    // Handle errors
    if (result.errors) {
      reporter.panicOnBuild(`Error while running GraphQL query.`)
      return
    }

    result.data.allMarkdownRemark.nodes.forEach( post => {
      createPage({
        path: post.frontmatter.slug,
        component: post.frontmatter.template === 'indexTemplate' ? indexTemplate : postTemplate, // Here is where the ugly "magic" happens...
        context: {
          slug: post.frontmatter.slug,
        },
      })
    })
  }

最佳答案

使用 gatsby-node.js 的想法是使用 createPage API 从某些数据源(CMS、Markdown 文件、JSON 文件、外部 API 等)创建动态页面。 。换句话说,创建具有来自数据源的未知 slug 或名称的动态页面确实很有用。这个想法是查询所有类型的数据(例如帖子)并通过上下文传递一些唯一信息(通常是 slugid)作为过滤器参数来执行另一个操作在模板中查询。

就您而言,这适合您的博客(markdown 文件 2),但不适用于其他已知页面,例如索引、关于等(markdown 文件 1)。它们是已定义的已知页面,应使用 page query 进行区别对待。 。它们不是模板,因为它们是独特的页面,您不会有两个可以重用主页模板的不同主页。

例如,要识别帖子和主页之间的不同 Markdown 页面,您可以使用 key 值来过滤查询。

---
title: 'Index page'
slug: '/'
key: 'home'
template: indexTemplate //This is where i declare which component it shall use
content: 'Index content'
---
Content of the index page.

还有:

---
slug: '/my-first-post'
date: '2019-05-04'
key: 'post'
title: 'My first blog post!'
content: 'Content post 1'
template: postTemplate
---

动态创建页面时(通过 gatsby-node.js),方法应如下所示:

const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const result = await graphql(`
    query {
      allMarkdownRemark(
        filter: { frontmatter: { key: { eq: "article" }}}) {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)

  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/templates/blog-post.js`),
      context: {
        // Data passed to context is available
        // in page queries as GraphQL variables.
        slug: node.fields.slug,
      },
    })
  })
}

注意key值的过滤器。

然后,在您的博客文章(模板)中:

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

export default function BlogPost({ data }) {
  const post = data.markdownRemark
  return (
    <Layout>
      <div>
        <h1>{post.frontmatter.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post.html }} />
      </div>
    </Layout>
  )
}

export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
    }
  }
`

对于您的静态页面,只需在页面上进行查询即可。对于您的 index.js:

import React from 'react'
import { graphql } from 'gatsby'

 const HomePage = ({data}) => {
  return (
    <div>
     Your page title is {data.nodes[0].frontmatter.title}
    </div>
  )
}

export const query = graphql`
  query HomePageQuery {
    allMarkdownRemark(filter: { frontmatter: { key: { eq: "home" }}}) {
       nodes{
         frontmatter{
           title
         }
       }
    }
  }
`

export default HomePage

请随意调整代码以满足您的需求。重要的是,您应该区分应用作模板的内容(博客、帖子、文章或其他动态数据)和应静态处理的内容(主页、关于或其他静态页面)。


当然,根据问题的范围,您可以有多个模板,一个用于帖子,另一个用于评论(或其他动态数据)。您可以简单地通过将查询结果保存在变量中并调用两次 createPage API 来实现它:

const result1 = await graphql(`
    query{
      allMarkdownRemark {
        nodes {
          frontmatter {
            slug
            template
          }
        }
      }
    }
  `)

const result2 = await graphql(`
    query{
      allMarkdownRemark {
        nodes {
          frontmatter {
            slug
            template
          }
        }
      }
    }
  `)

  const postTemplate = require.resolve(`./src/templates/postTemplate.js`)
  const reviewsTemplate = require.resolve(`./src/templates/reviewsTemplate.js`)
    // Handle errors
    if (result1.errors || result2.errors) {
      reporter.panicOnBuild(`Error while running GraphQL query.`)
      return
    }

    result1.data.allMarkdownRemark.nodes.forEach( post => {
      createPage({
        path: post.frontmatter.slug,
        component: postTemplate
        context: {
          slug: post.frontmatter.slug,
        },
      })
    })

    result2.data.allMarkdownRemark.nodes.forEach( review => {
      createPage({
        path: review.frontmatter.slug,
        component: reviewsTemplate
        context: {
          slug: review.frontmatter.slug,
        },
      })
    })

关于reactjs - Gatsby.js 中的多个模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64677182/

相关文章:

javascript - 路径更改时 Webpack 从错误的 URL 加载

c# - 如何永久为所有查询请求启用 Apollo Tracing with Hot Chocolate?

javascript - 如何在 aws 放大中使用 graphQL 限制

documentation - markdown/pandoc 的全站编译?

html - 使用 nbconvert 运行笔记本时,IPython 显示器不显示 Markdown

html - 如何告诉 tumblr 停止更改 Markdown 和/或 HTML 代码?

javascript - defaultValue 不会改变...下拉 react

javascript - 由于来自本地主机的 CORS 问题导致请求失败

reactjs - 警告 : Expected server HTML to contain a matching <section> in <div>. ---- Next.js/react

go - 从 Golang 应用程序使用 GraphQL 服务