Gatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置
Posted
技术标签:
【中文标题】Gatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置【英文标题】:GraphQL queries for Gatsby - Contentful setup with a flexible content model 【发布时间】:2019-01-20 12:46:41 【问题描述】:我有一个 gatsby 网站,其中包含 contentful 插件 和 graphql 查询(设置正常)。
[编辑] 我的 gatsby 设置使用 pageCreate 功能动态提取数据。并填充我的模板组件,即我在下面共享的根 graphql 查询。如果内容页面遵循以下查询中给出的结构,我可以使用设置创建多个页面。 [/编辑]
我的问题是关于我似乎遇到的一个限制,或者只是不知道足够的 grpahql 来理解这一点。
我的高级内容模型“BasicPageLayout”包含通过字段“Section”对其他内容类型的引用。因此,在“BasicPageLayout”中包含哪些内容类型以及添加它们的顺序方面,它是灵活的。
根页面查询
export const pageQuery = graphql`
query basicPageQuery
contentfulBasicPageLayout(pageName: eq: "Home")
heroSection
parent
id
...HeroFields
section1
parent
id
...ContentText
section2
parent
id
...ContentTextOverMedia
section3
parent
id
...ContentTextAndImage
section4
parent
id
...ContentText
内容类型片段都存在于各自的 UI 组件中。 上述查询和设置工作正常。
现在,我对“Home”进行了硬编码,因为我无法创建灵活的可重用查询。我在创建模型时利用了 contentful 的灵活特性,但还没有找到一种方法在 graphql 查询中为其创建这种灵活性。
我所知道的: Graphql 查询是在运行时解析的,因此需要获取的所有内容都应该在该查询中。它不能是“动态的”。
问题: basicPageLayout 中的“Section”字段可以链接到任何内容类型。所以我们可以混合和匹配粒度级别的内容类型。如何添加内容类型片段(如 ContentTextAndImage 与 ContentText),使其适合该部分实例(查询中的“Section”字段)?
换句话说 我希望根查询获取可能有 4 个部分的“主页”数据,所有类型 - ContentTextOverMedia 以及可能也有 4 个部分但类型交替的“关于”数据 - ContentText 和 ContentTextAndImage
这是目标,因为我想通过在内容上混合匹配内容类型来创建内容(页面),而无需在每次创建新页面时更新代码。这就是为什么 Contentful 很有用并且首先被选中的原因。
到目前为止我的想法:
A.连续运行两个查询。一个获取每个部分的 parent.id 并保存内容类型信息。第二次使用适当的片段获取数据。
B.通过 Contentful API 分别获取 basicPageLayouts 内容实例(例如“Home”)的 JSON 文件,并使用该 JSON 文件创建要在每个实例中使用的 graphql 字符串(因此,Home、About 等不同的布局) 这需要更多的实验,不确定它是否可行,也可能比它需要的更复杂。
所以,请分享我正在探索的上述路径或我没有考虑使用 graphql 或 gatsby 功能的其他解决方案的想法。
这是我关于 SO btw 的第一个问题,我花了一些时间来完善它并尝试遵循指南,但请务必在 cmets 中给我反馈,这样即使您没有我的答案,我也可以改进题。 提前致谢。
【问题讨论】:
【参考方案1】:如果我理解正确,您想根据来自 Contentful 的数据动态创建页面。
您可以使用 Gatsbyjs 节点 API 特别是 createPage
来实现这一点。
在您的gatsby-node.js
文件中,您可以拥有类似的内容
const fs = require('fs-extra')
const path = require('path')
exports.createPages = (graphql, boundActionCreators) =>
const createPage = boundActionCreators
return new Promise((resolve, reject) =>
const landingPageTemplate = path.resolve('src/templates/landing-page.js')
resolve(
graphql(`
allContentfulBesicPageLayout
edges
node
pageName
`).then((result) =>
if (result.errors)
reject(result.errors)
result.data.allContentfulBesicPageLayout.edges.forEach((edge) =>
createPage (
path: `$edge.node.pageName`,
component: landingPageTemplate,
context:
slug: edge.node.pageName // this will passed to each page gatsby create
)
)
return
)
)
)
现在在你的src/templates/landing-page.js
import React, Component from 'react'
const LandingPage = (data) =>
return (<div>Add you html here</div>)
export const pageQuery = graphql`
query basicPageQuery($pageName: String!)
contentfulBasicPageLayout(pageName: eq: $pageName)
heroSection
parent
id
...HeroFields
section1
parent
id
...ContentText
section2
parent
id
...ContentTextOverMedia
section3
parent
id
...ContentTextAndImage
section4
parent
id
...ContentText
注意$pageName
参数,这是在创建页面时传递给组件上下文的内容。
这样,您最终将创建任意数量的页面。
请注意:代码的反应部分没有经过测试,但我希望你明白。
更新: 要进行灵活的查询,而不是将内容类型作为单个 ref 字段,您可以拥有一个名为 section 的字段,您可以按您想要的顺序在其中添加您想要的部分。 您的查询将如下所示
export const pageQuery = graphql`
query basicPageQuery($pageName: String!)
contentfulBasicPageLayout(pageName: eq: $pageName)
sections
... on ContentfulHeroFields
internal
type
哈立德
【讨论】:
感谢您的回答哈立德。当我开始这个项目时,我看了你内容丰富的 + gatsby 系列,它非常有用,所以也谢谢你。澄清:我已经让 pageCreate 工作了,如果我将多个页面添加到内容完全相同的结构中,它会动态工作。问题在于查询结构的灵活性。对于其他页面,我可能想要具有不同内容类型的部分或不同顺序的部分,但希望使用相同的模板(布局),因为内容上的顺序/内容类型可能会经常更改。 啊,好吧,那么您可以拥有一个名为 section 的字段,而不是将您的内容类型作为单个 ref 字段,您可以按照您想要的顺序添加您想要的部分。我会更新答案 好的,所以一个字段(多参考?)包含按所需顺序的所有部分 - 这也适用于组织内容和传达顺序。但是,关于如何识别每个部分的值是什么(什么内容类型)以便将其字段放入查询中的问题仍然存在。由于必须在运行时知道这些内容类型字段。如果问题需要更多信息,请告诉我! 这是... on Contentful[YourSectionContentType]
的一部分,基于 internal.type 渲染块。我在这里做了类似的事情:github.com/Khaledgarbaya/chocolate-free-website/blob/master/src/…
啊,所以对于每个部分的值,通过对每个片段使用“打开”功能,覆盖了任何已定义内容类型的可能性。那太棒了!感谢您编辑答案。以上是关于Gatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有 gatsby 的 graphql 查询中使用正则表达式
Gatsby:graphql 查询中的 gatsby-source-graphql 和 gatsby-plugin-sharp