You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gatsby GraphQL如何动态查询当前目录下的MDX页面

Gatsby 动态过滤同目录MDX页面实现方案

你不需要在组件运行时通过location做客户端过滤,Gatsby 原生支持在构建阶段通过页面上下文(Page Context)向 GraphQL 查询传参,直接实现动态正则过滤,步骤如下:


1. 在创建页面时注入过滤参数

所有页面的 GraphQL 查询可访问的动态参数都来自createPage时传入的context字段,你只需要在生成目录索引页时,提前计算好当前目录对应的匹配正则,传入上下文即可。
如果你是通过gatsby-node.js的createPages API 手动生成页面,参考如下逻辑:

const path = require('path')

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions
  // 拉取所有MDX节点数据
  const mdxResult = await graphql(`
    query {
      allMdx { nodes { slug } }
    }
  `)
  if (mdxResult.errors) reporter.panicOnBuild('MDX数据加载失败', mdxResult.errors)

  // 替换成你实际的目录列表生成逻辑,这里仅做示例
  const allDirectories = ['', 'sub/', 'sub/subsub/']
  allDirectories.forEach(currentDir => {
    // 生成匹配当前目录直属页面的正则:仅匹配当前目录下一级文件,排除子目录内容
    const matchRegex = new RegExp(`^${currentDir}[^/]+/?$`).toString()
    createPage({
      path: currentDir ? `/blog/${currentDir}` : '/blog',
      component: path.resolve('./src/pages/blog.js'), // 替换成你实际的列表页组件路径
      context: {
        directorySlugRegex: matchRegex
      }
    })
  })
}

如果你是用插件自动生成页面,不想手写全量createPages逻辑,可以用onCreatePage钩子拦截索引页的创建过程,给对应页面追加正则参数:

exports.onCreatePage = ({ page, actions }) => {
  const { createPage, deletePage } = actions
  // 仅处理博客目录索引页,根据你的实际路由规则调整判断条件
  if (page.path.startsWith('/blog')) {
    deletePage(page)
    // 提取当前页面对应的目录路径
    const currentDir = page.path.replace(/^\/blog\//, '').replace(/\/$/, '')
    const regexStr = new RegExp(`^${currentDir ? currentDir + '/' : ''}[^/]+/?$`).toString()
    createPage({
      ...page,
      context: {
        ...page.context,
        directorySlugRegex: regexStr
      }
    })
  }
}

2. 修改页面组件的GraphQL查询接收参数

把原来硬编码的正则替换成上下文传入的变量即可,Gatsby 会自动将context中的字段映射为查询的可用变量:

import * as React from 'react'
import { Link, graphql } from 'gatsby'
import Layout from '../../components/layout'

const BlogPage = ({ data }) => {
  return (
    <Layout pageTitle="My Blog Posts">
      {
        data.allMdx.nodes.map(node => (
          <article key={node.id}>
            <h2>
              <Link to={`/blog/${node.slug}`}>
                {node.frontmatter.title}
              </Link>
            </h2>
            <p>Posted: {node.frontmatter.date}</p>
          </article>
        ))
      }
    </Layout>
  )
}

export const query = graphql`
  query BlogListQuery($directorySlugRegex: String!) {
    allMdx(
      sort: {fields: frontmatter___date, order: DESC}
      filter: {slug: {regex: $directorySlugRegex}}
    ) {
      nodes {
        frontmatter {
          date(formatString: "D MMMM YYYY")
          title
        }
        id
        slug
      }
    }
  }
`

export default BlogPage

注意事项

  • 所用正则^${currentDir}[^/]+/?$和你之前硬编码的过滤逻辑完全一致:仅返回当前目录下的直属页面,不会嵌套返回子目录下的内容。
  • 所有过滤逻辑在构建阶段完成,不需要在客户端运行时处理路径,没有内容闪烁问题,性能更好。
  • 变量名可以自定义,只要createPage时传入的context字段名和GraphQL查询里的变量名保持一致即可。

内容的提问来源于stack exchange,提问作者Jasper Citi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:27:18