如何创建单个 Gatsby 页面以按标签/类别显示和过滤所有博客文章

Posted

技术标签:

【中文标题】如何创建单个 Gatsby 页面以按标签/类别显示和过滤所有博客文章【英文标题】:How to create a single Gatsby Page to show and filter all blog posts by tag/category 【发布时间】:2021-05-19 02:35:53 【问题描述】:

您好,我正在使用 Gatsby 和 Netlify CMS 构建博客。我从 gatsby-starter-netlify-cms 模板开始。

我有/blog 页面,我目前在其中显示所有帖子以及所有标签的列表。 当用户点击一个标签时,它当前会被重定向到tags/name-of-tag 页面,该页面会显示所有带有此类标签的帖子的列表。

我想要的是直接过滤/blog页面上的列表。 这样,我将只有一个页面来按标签(也可能按字词搜索)显示和过滤博客文章。

所以标签链接应该重定向到/blog?tag-name 或类似的东西。 我不确定如何告诉 Gatsby 创建一个可以注入 filter 值的单个页面,以便将其传递给页面查询..

/tags/ 页面目前是这样创建的:

// Tag pages:
    let tags = []
    // Iterate through each post, putting all found tags into `tags`
    posts.forEach((edge) => 
      if (_.get(edge, `node.frontmatter.tags`)) 
        tags = tags.concat(edge.node.frontmatter.tags)
      
    )
    // Eliminate duplicate tags
    tags = _.uniq(tags)

    // Make tag pages
    tags.forEach((tag) => 
      const tagPath = `/tags/$_.kebabCase(tag)/`

      createPage(
        path: tagPath,
        component: path.resolve(`src/templates/tags.js`),
        context: 
          tag,
        ,
      )
    )

这是我的博客页面查询(我希望能够按标签过滤):

export const blogPageQuery = graphql`
  query BlogPageTemplate 
    markdownRemark(frontmatter:  templateKey:  eq: "blog-page"  ) 
      frontmatter 
        image 
          childImageSharp 
            fluid(maxWidth: 2048, quality: 80) 
              ...GatsbyImageSharpFluid
            
          
        
        heading
        subheading
      
    
    allMarkdownRemark(
      sort:  order: DESC, fields: [frontmatter___date] 
      filter:  frontmatter:  templateKey:  eq: "blog-post"   
    ) 
      edges 
        node 
          id
          fields 
            slug
          
          excerpt(pruneLength: 180)
          frontmatter 
            date(formatString: "MMMM DD, YYYY")
            title
            description
            featuredpost
            featuredimage 
              childImageSharp 
                fluid(quality: 50, maxWidth: 512) 
                  ...GatsbyImageSharpFluid
                
              
            
          
        
      
    
  
`

【问题讨论】:

到目前为止你尝试了什么? 我想在从页面查询中获取所有帖子的数组后直接过滤列表,但是我不知道如何从另一个链接触发过滤(比如点击博客帖子标签在另一页)。最好的办法是使用 gatsby 的页面节点创建和 graphql,但我不知道如何.. 【参考方案1】:

我不知道如何告诉 Gatsby 创建一个单独的页面 注入filter 值以将其传递到页面的可能性 查询。

你不能。在页面查询中过滤数据的唯一方法是使用上下文传递数据。就像您在标签页面中所做的那样:

  createPage(
    path: tagPath,
    component: path.resolve(`src/templates/tags.js`),
    context: 
      tag,
    ,
  )

最简单的原生方法是使用/tag/tag-name页面,该页面旨在按标签名称过滤,否则,您将需要获取URL参数并在javascript filter函数中使用它来过滤所有来自页面查询的数据。由于您缺少博客页面的渲染部分......这种方法应该可以工作:

const BlogTemplate=( data )
    if(typeof window !== "undefined")
      const queryString = window.location.search;
      const urlParams = new URLSearchParams(queryString);
      const urlTag= urlParams.get('tag');
      const filteredPosts= data.allMarkdownRemark.edges.node.filter(node=> node.frontmatter.tag.includes(urlTag))
      const loopData= urlParams.has('tag') ? filteredPosts : data
   
   
return loopData.allMarkdownRemark.edges.node.map(node=> <h1 key=node.title>node.title</h1>)


注意:当然,根据你的需要调整它,但要明白。

另请注意,您需要将所有窗口逻辑包装在typeof window !== "undefined" 条件中,因为in the s-s-r window (and other global objects) are not available。

关键部分是使用data还是你的filteredPosts取决于URL参数的存在,所以如果存在,你需要过滤数据,否则你需要使用“默认” data(未过滤)。

很难猜测代码的行为方式,但这个想法依赖于根据 URL 更改可迭代数据,如果需要,请使用一些钩子。

根据您的查询,您的博客在博客模板查询中似乎不包含任何 tag 字段,因此您需要添加它以允许 filter 循环工作。

代码运行后,您需要添加适当的控件以避免在缺少某些字段时出现代码破坏,但思路和路径是这样的。

【讨论】:

你的代码很有魅力(在适应了我的变量名等之后),谢谢!我得到的唯一错误来自这一行:const filteredPosts= data.allMarkdownRemark.edges.node.filter(node=&gt; node.frontmatter.tag.includes(urlTag)) 应该是 const filteredPosts= data.allMarkdownRemark.edges.node.filter(node=&gt; return node.frontmatter.tag.includes(urlTag)) 因为 .filter 没有返回对象

以上是关于如何创建单个 Gatsby 页面以按标签/类别显示和过滤所有博客文章的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 reactjs 和 graphql 在 gatsby 中映射嵌套数组

使用 gatsby-plugin-categories / gatsby-plugin-tags 标记云和类别列表

基于许多内容引用使用 Gatsby 动态创建页面

已部署的页面加载但不显示--用gatsby构建。

如何在带有 gatsby 的 graphql 查询中使用正则表达式

如何使用 Gatsby 显示 Contentul 图像