使用 markdown 在 Gatsby Layout 组件中动态添加页面元数据
Dynamically adding page meta in Gatsby Layout component using markdown
我的objective:
将代码添加到 Layout 组件,以便根据 frontmatter 中提供的内容,使用用户所在的当前页面更新元标题、描述和图像。例如,如果用户导航到关于页面,元数据应显示以下内容:
<title>About | Website</title>
<meta content="This is the about page" name="description">
<link rel="canonical" href="www.website.com/about" />
<meta property="og:image" content="/images/about-meta.png" />
而在关于页面上相应的元是这样的:
---
title: About
description: This is the about page
meta_image: /images/about-meta.png
slug: about
---
我现在在做什么:
我将 Helmet 标签中的所有信息添加到各个模板,并且我在布局中设置了标题模板,但似乎必须有更好的方法来自动设置布局中的 Helmet 组件以读取它.
Layout.jsx
<Helmet
defaultTitle={siteMetadata.title}
titleTemplate={`%s | ${siteMetadata.title}`}
/>
templates/about.jsx
<Helmet title={frontmatter.title} >
<meta property="og:image" content={frontmatter.meta_image}/>
<link rel="canonical" href="{siteMetadata.siteUrl}/{frontmatter.slug}" />
</Helmet>
Gatsby 有这个关于创建 SEO component 的指南,但它不包括它如何从页面模板工作并使用行话来定义行话,所以它对我作为反应菜鸟不是特别有用。我不太了解 PropTypes 是什么或它们的作用。
我在尝试什么:
我想在布局中添加一个静态查询,该查询将检测当前页面 slug,然后根据当前 slug 获取 markdownremark 并动态填充元数据,这样我就不必为每个页面模板添加 helmet 标签。
What I'm trying: I'd like to add a static query within the layout that will detect the current page slug then fetch the markdownremark
based on the current slug and dynamically fill in the meta data so I
don't have to add a helmet tag per page template.
这种方法是有效的,但是当您试图避免在每个页面模板中添加 SEO
组件时,您正在改变组件的职责。在我看来,在 SEO
组件中,您 必须 放置 useStaticQuery
(或 StaticQuery
)将在每次页面更改时触发的内容,不在 Layout
中,它的唯一职责是显示整个站点的共享布局,而不是查询。此外,您可能会在孤立的页面(关于等)中进行页面查询,因此您已经在获取数据,因此没有必要不添加一些额外的行来在那里添加 SEO。
此外,您将无法在 Layout
中添加查询,因为您只有两个选择:
- 添加 page query:这不是一个选项,因为它仅适用于 top-level 组件(页面或模板)。
Layout
是 none.
- 在
Layout
中添加 useStaticQuery
:也不是一个选项,因为您不能添加动态参数(如 slug
或类似参数)。这是一个 known limitation.
事实上,它位于您确切知道页面本身的元数据是什么的页面上,因此在您希望拥有所有 SEO 的每个特定页面上使用 SEO
组件更容易和最干净元数据。
如果您在布局中查询内容,您将不必要地提升 props
,因为它们总是会被提取、更改和向下钻取。
创建一个 SEO
组件,例如:
const SEO = ({ description, lang= "en-US", meta, title }) => {
const { site } = useStaticQuery(graphql`
query getAllMetadata {
site {
siteMetadata {
title
description
author
}
}
}
`,
);
const metaDescription = description ?? site.siteMetadata.description;
return <Helmet htmlAttributes={{ lang }} title={title} titleTemplate={`%s | ${site.siteMetadata.title}`}>
<meta name={`robots`} content={`index, follow`}/>
<meta name={`description`} content={metaDescription}/>
<meta name={`og:title`} content={title}/>
<meta name={`og:description`} content={metaDescription}/>
<meta name={`og:type`} content={`website`}/>
<meta name={`twitter:card`} content={`summary`}/>
<meta name={`twitter:creator`} content={site.siteMetadata.author}/>
<meta name={`twitter:title`} content={title}/>
<meta name={`twitter:description`} content={metaDescription}/>
</Helmet>;
};
export default SEO;
您将查询特定于组件中的共享元数据(title
、description
和 author
在本例中,添加到 siteMetadata
对象中gatsby-config.js
) 而与此同时,该组件仍在为放置它的每个特定页面的每个特定字段接收所需的数据(如 props
)。
我的objective: 将代码添加到 Layout 组件,以便根据 frontmatter 中提供的内容,使用用户所在的当前页面更新元标题、描述和图像。例如,如果用户导航到关于页面,元数据应显示以下内容:
<title>About | Website</title>
<meta content="This is the about page" name="description">
<link rel="canonical" href="www.website.com/about" />
<meta property="og:image" content="/images/about-meta.png" />
而在关于页面上相应的元是这样的:
---
title: About
description: This is the about page
meta_image: /images/about-meta.png
slug: about
---
我现在在做什么: 我将 Helmet 标签中的所有信息添加到各个模板,并且我在布局中设置了标题模板,但似乎必须有更好的方法来自动设置布局中的 Helmet 组件以读取它.
Layout.jsx
<Helmet
defaultTitle={siteMetadata.title}
titleTemplate={`%s | ${siteMetadata.title}`}
/>
templates/about.jsx
<Helmet title={frontmatter.title} >
<meta property="og:image" content={frontmatter.meta_image}/>
<link rel="canonical" href="{siteMetadata.siteUrl}/{frontmatter.slug}" />
</Helmet>
Gatsby 有这个关于创建 SEO component 的指南,但它不包括它如何从页面模板工作并使用行话来定义行话,所以它对我作为反应菜鸟不是特别有用。我不太了解 PropTypes 是什么或它们的作用。
我在尝试什么: 我想在布局中添加一个静态查询,该查询将检测当前页面 slug,然后根据当前 slug 获取 markdownremark 并动态填充元数据,这样我就不必为每个页面模板添加 helmet 标签。
What I'm trying: I'd like to add a static query within the layout that will detect the current page slug then fetch the markdownremark based on the current slug and dynamically fill in the meta data so I don't have to add a helmet tag per page template.
这种方法是有效的,但是当您试图避免在每个页面模板中添加 SEO
组件时,您正在改变组件的职责。在我看来,在 SEO
组件中,您 必须 放置 useStaticQuery
(或 StaticQuery
)将在每次页面更改时触发的内容,不在 Layout
中,它的唯一职责是显示整个站点的共享布局,而不是查询。此外,您可能会在孤立的页面(关于等)中进行页面查询,因此您已经在获取数据,因此没有必要不添加一些额外的行来在那里添加 SEO。
此外,您将无法在 Layout
中添加查询,因为您只有两个选择:
- 添加 page query:这不是一个选项,因为它仅适用于 top-level 组件(页面或模板)。
Layout
是 none. - 在
Layout
中添加useStaticQuery
:也不是一个选项,因为您不能添加动态参数(如slug
或类似参数)。这是一个 known limitation.
事实上,它位于您确切知道页面本身的元数据是什么的页面上,因此在您希望拥有所有 SEO 的每个特定页面上使用 SEO
组件更容易和最干净元数据。
如果您在布局中查询内容,您将不必要地提升 props
,因为它们总是会被提取、更改和向下钻取。
创建一个 SEO
组件,例如:
const SEO = ({ description, lang= "en-US", meta, title }) => {
const { site } = useStaticQuery(graphql`
query getAllMetadata {
site {
siteMetadata {
title
description
author
}
}
}
`,
);
const metaDescription = description ?? site.siteMetadata.description;
return <Helmet htmlAttributes={{ lang }} title={title} titleTemplate={`%s | ${site.siteMetadata.title}`}>
<meta name={`robots`} content={`index, follow`}/>
<meta name={`description`} content={metaDescription}/>
<meta name={`og:title`} content={title}/>
<meta name={`og:description`} content={metaDescription}/>
<meta name={`og:type`} content={`website`}/>
<meta name={`twitter:card`} content={`summary`}/>
<meta name={`twitter:creator`} content={site.siteMetadata.author}/>
<meta name={`twitter:title`} content={title}/>
<meta name={`twitter:description`} content={metaDescription}/>
</Helmet>;
};
export default SEO;
您将查询特定于组件中的共享元数据(title
、description
和 author
在本例中,添加到 siteMetadata
对象中gatsby-config.js
) 而与此同时,该组件仍在为放置它的每个特定页面的每个特定字段接收所需的数据(如 props
)。