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

Next.js无前缀多层动态路由实现及最佳实践咨询

Next.js 无前缀多层分类路由最佳实践

针对你的需求,直接上可行的落地方案,分Pages Router(旧版)和App Router(Next.js 13+)两种场景说明:

核心思路

不用在根目录乱建单个动态文件,而是利用Next.js路由优先级规则(静态路由 > 动态路由 > 捕获所有路由),结合捕获所有动态路由来处理多层分类路径,同时单独创建静态页面(如aboutus)避免被分类路由误匹配。


方案一:Pages Router(Next.js 12及以下)

  1. 创建静态页面
    直接在pages目录下建aboutus.js,这个静态路由会优先匹配/aboutus,永远不会走到分类路由逻辑里。

  2. 创建捕获所有分类路由
    在pages目录下建[...slug].js,这个文件会匹配所有未被静态路由覆盖的多层路径(如/mobile/ios/apple/iphone-14)。

  3. 在[...slug].js里区分层级并渲染对应页面
    通过slug数组的长度判断当前层级,再渲染对应的页面组件,同时加入路径有效性验证避免非法访问:

    // pages/[...slug].js
    import CategoryPage from '../components/CategoryPage';
    import SubCategoryPage from '../components/SubCategoryPage';
    import BrandPage from '../components/BrandPage';
    import ProductPage from '../components/ProductPage';
    import NotFound from '../components/NotFound';
    
    export default function DynamicRoute({ slug, pageType, data }) {
      switch(pageType) {
        case 'category':
          return <CategoryPage category={slug[0]} data={data} />;
        case 'subcategory':
          return <SubCategoryPage category={slug[0]} subcategory={slug[1]} data={data} />;
        case 'brand':
          return <BrandPage category={slug[0]} subcategory={slug[1]} brand={slug[2]} data={data} />;
        case 'product':
          return <ProductPage category={slug[0]} subcategory={slug[1]} brand={slug[2]} product={slug[3]} data={data} />;
        default:
          return <NotFound />;
      }
    }
    
    export async function getServerSideProps(context) {
      const { slug } = context.params;
      let pageType = null;
      let data = null;
    
      // 验证路径合法性:比如检查第一个slug是否是存在的分类
      const validCategories = ['mobile', 'laptop', 'home'];
      if (slug.length >=1 && !validCategories.includes(slug[0])) {
        return { notFound: true };
      }
    
      // 根据层级获取对应数据
      switch(slug.length) {
        case 1:
          pageType = 'category';
          data = await fetch(`/api/categories/${slug[0]}`).then(res => res.json());
          break;
        case 2:
          pageType = 'subcategory';
          data = await fetch(`/api/categories/${slug[0]}/subcategories/${slug[1]}`).then(res => res.json());
          break;
        case 3:
          pageType = 'brand';
          data = await fetch(`/api/categories/${slug[0]}/subcategories/${slug[1]}/brands/${slug[2]}`).then(res => res.json());
          break;
        case 4:
          pageType = 'product';
          data = await fetch(`/api/categories/${slug[0]}/subcategories/${slug[1]}/brands/${slug[2]}/products/${slug[3]}`).then(res => res.json());
          break;
        default:
          return { notFound: true };
      }
    
      // 如果数据不存在,返回404
      if (!data) return { notFound: true };
    
      return {
        props: { slug, pageType, data }
      };
    }
    

方案二:App Router(Next.js 13+)

App Router的写法更简洁,逻辑类似:

  1. 创建静态页面
    在app目录下建aboutus/page.js,静态路由优先匹配。

  2. 创建捕获所有分类路由
    在app目录下建[...slug]/page.js,处理所有多层分类路径。

  3. 异步获取数据并渲染对应页面

    // app/[...slug]/page.js
    import CategoryPage from './CategoryPage';
    import SubCategoryPage from './SubCategoryPage';
    import BrandPage from './BrandPage';
    import ProductPage from './ProductPage';
    import NotFound from '../NotFound';
    
    // 封装数据获取和路径验证逻辑
    async function getPageContext(slug) {
      const validCategories = ['mobile', 'laptop', 'home'];
      // 验证根分类合法性
      if (slug.length >=1 && !validCategories.includes(slug[0])) {
        return { valid: false };
      }
    
      // 根据层级获取数据
      switch(slug.length) {
        case 1:
          return {
            valid: true,
            type: 'category',
            data: await fetch(`/api/categories/${slug[0]}`).then(res => res.json())
          };
        case 2:
          return {
            valid: true,
            type: 'subcategory',
            data: await fetch(`/api/categories/${slug[0]}/subcategories/${slug[1]}`).then(res => res.json())
          };
        case 3:
          return {
            valid: true,
            type: 'brand',
            data: await fetch(`/api/categories/${slug[0]}/subcategories/${slug[1]}/brands/${slug[2]}`).then(res => res.json())
          };
        case 4:
          return {
            valid: true,
            type: 'product',
            data: await fetch(`/api/categories/${slug[0]}/subcategories/${slug[1]}/brands/${slug[2]}/products/${slug[3]}`).then(res => res.json())
          };
        default:
          return { valid: false };
      }
    }
    
    export default async function SlugPage({ params }) {
      const { slug } = params;
      const pageContext = await getPageContext(slug);
    
      if (!pageContext.valid || !pageContext.data) {
        return <NotFound />;
      }
    
      // 根据层级渲染对应组件
      switch(pageContext.type) {
        case 'category':
          return <CategoryPage data={pageContext.data} />;
        case 'subcategory':
          return <SubCategoryPage data={pageContext.data} />;
        case 'brand':
          return <BrandPage data={pageContext.data} />;
        case 'product':
          return <ProductPage data={pageContext.data} />;
        default:
          return <NotFound />;
      }
    }
    

关键注意事项

  1. 路由优先级:静态页面(如aboutus)会优先被匹配,完全不用担心被分类路由覆盖。
  2. 路径验证:必须在数据获取阶段验证路径合法性,避免用户输入非法路径(如/random/xxx)返回错误内容。
  3. 组件拆分:把不同层级的页面拆成独立组件,代码更易维护,也方便复用逻辑。
  4. 静态生成优化:如果你的分类数据是静态的,可以用getStaticPaths(Pages Router)或generateStaticParams(App Router)预生成所有路径,提升访问速度;数据动态更新的话,用增量静态再生(ISR)。

内容的提问来源于stack exchange,提问作者Jack The Baker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 19:05:29