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
相关产品推荐
相关产品推荐

