Next.js 文件系统路由深度解析:从原理到实践

文章目录

    • 一、文件系统路由核心概念
      • [1.1 什么是文件系统路由?](#1.1 什么是文件系统路由?)
      • [1.2 工作原理架构图](#1.2 工作原理架构图)
    • 二、基础路由配置
      • [2.1 静态路由](#2.1 静态路由)
      • [2.2 路由映射关系表](#2.2 路由映射关系表)
    • 三、动态路由详解
      • [3.1 基础动态路由](#3.1 基础动态路由)
      • [3.2 可选捕获所有段路由](#3.2 可选捕获所有段路由)
    • 四、路由参数与数据获取
      • [4.1 预渲染数据获取](#4.1 预渲染数据获取)
      • [4.2 路由查询参数处理](#4.2 路由查询参数处理)
    • 五、路由导航与链接
      • [5.1 客户端导航](#5.1 客户端导航)
      • [5.2 编程式导航](#5.2 编程式导航)
      • [5.3 路由事件监听](#5.3 路由事件监听)
    • 六、高级路由模式
      • [6.1 并行路由和拦截路由](#6.1 并行路由和拦截路由)
      • [6.2 动态导入与路由分组](#6.2 动态导入与路由分组)
      • [6.3 中间件与路由保护](#6.3 中间件与路由保护)
    • 七、路由优化策略
      • [7.1 预加载策略](#7.1 预加载策略)
      • [7.2 滚动恢复与保持](#7.2 滚动恢复与保持)
    • [八、API 路由系统](#八、API 路由系统)
      • [8.1 基础API路由](#8.1 基础API路由)
      • [8.2 动态API路由](#8.2 动态API路由)
    • 九、最佳实践与常见问题
      • [9.1 路由组织结构最佳实践](#9.1 路由组织结构最佳实践)
      • [9.2 常见问题与解决方案](#9.2 常见问题与解决方案)
    • 十、性能优化与监控
      • [10.1 路由性能监控](#10.1 路由性能监控)
      • [10.2 路由缓存策略](#10.2 路由缓存策略)
    • 总结

一、文件系统路由核心概念

1.1 什么是文件系统路由?

文件系统路由是 Next.js 的核心特性之一,它通过文件目录结构自动生成应用的路由系统。这意味着文件即路由,无需手动配置路由表。

复制代码
📁 pages/
  ├── index.js           → https://example.com/
  ├── about.js          → https://example.com/about
  ├── blog/
  │   ├── index.js      → https://example.com/blog
  │   └── [slug].js     → https://example.com/blog/:slug
  └── api/
      └── users.js      → https://example.com/api/users

1.2 工作原理架构图

复制代码
┌─────────────────────────────────────────────┐
│          文件系统路由工作流程                 │
├─────────────────────────────────────────────┤
│  1. 文件创建于 pages/ 目录                  │
│  2. Next.js 编译时扫描目录结构              │
│  3. 生成路由映射表                          │
│  4. 创建对应的 React 组件                   │
│  5. 建立 URL 与组件的映射关系               │
│  6. 请求时匹配并渲染对应组件                │
└─────────────────────────────────────────────┘

二、基础路由配置

2.1 静态路由

基本页面创建

javascript 复制代码
// pages/index.js - 首页路由
export default function HomePage() {
  return <h1>欢迎访问首页</h1>;
}

// pages/about.js - 关于页面
export default function AboutPage() {
  return (
    <div>
      <h1>关于我们</h1>
      <p>这是关于页面内容</p>
    </div>
  );
}

// pages/contact.js - 联系页面
export default function ContactPage() {
  return (
    <div>
      <h1>联系我们</h1>
      <form>
        <input type="email" placeholder="邮箱" />
        <button type="submit">发送</button>
      </form>
    </div>
  );
}

嵌套文件夹路由

javascript 复制代码
// pages/products/index.js - 产品列表页
export default function ProductsPage() {
  return (
    <div>
      <h1>所有产品</h1>
      <ul>
        <li>产品1</li>
        <li>产品2</li>
      </ul>
    </div>
  );
}

// pages/products/featured.js - 特色产品页
export default function FeaturedProducts() {
  return <h1>特色产品</h1>;
}

2.2 路由映射关系表

文件路径 路由URL 访问方式
pages/index.js / 自动生成
pages/about.js /about 自动生成
pages/blog/index.js /blog 自动生成
pages/blog/first-post.js /blog/first-post 自动生成
pages/products/categories/index.js /products/categories 自动生成

三、动态路由详解

3.1 基础动态路由

单参数动态路由

javascript 复制代码
// pages/products/[id].js
import { useRouter } from 'next/router';

export default function ProductDetail() {
  const router = useRouter();
  const { id } = router.query;
  
  return (
    <div>
      <h1>产品详情页</h1>
      <p>产品ID: {id}</p>
      <p>产品名称: 产品{id}</p>
    </div>
  );
}

// 访问示例:
// /products/123 → id = "123"
// /products/abc → id = "abc"

多段动态路由

javascript 复制代码
// pages/category/[categoryId]/product/[productId].js
export default function CategoryProductDetail() {
  const router = useRouter();
  const { categoryId, productId } = router.query;
  
  return (
    <div>
      <h1>分类产品详情</h1>
      <p>分类ID: {categoryId}</p>
      <p>产品ID: {productId}</p>
    </div>
  );
}

// 访问示例:
// /category/electronics/product/iphone-13

3.2 可选捕获所有段路由

捕获所有路由

javascript 复制代码
// pages/docs/[...slug].js
export default function DocsPage() {
  const router = useRouter();
  const { slug = [] } = router.query;
  
  return (
    <div>
      <h1>文档页面</h1>
      <p>路径参数: {JSON.stringify(slug)}</p>
      <p>当前路径: /docs/{slug.join('/')}</p>
    </div>
  );
}

// 访问示例:
// /docs/getting-started → slug = ["getting-started"]
// /docs/api/v1/users → slug = ["api", "v1", "users"]

可选捕获所有路由

javascript 复制代码
// pages/blog/[[...slug]].js
export default function BlogPage() {
  const router = useRouter();
  const { slug } = router.query;
  
  return (
    <div>
      <h1>博客页面</h1>
      {slug ? (
        <p>查看具体文章: {slug.join('/')}</p>
      ) : (
        <p>博客首页 - 显示所有文章</p>
      )}
    </div>
  );
}

// 访问示例:
// /blog → 显示博客首页
// /blog/react-tutorial → 显示具体文章
// /blog/category/tutorials → 显示分类文章

四、路由参数与数据获取

4.1 预渲染数据获取

getStaticPaths + getStaticProps(SSG)

javascript 复制代码
// pages/products/[id].js
import { useRouter } from 'next/router';

// 1. 定义所有可能的路径
export async function getStaticPaths() {
  // 在实际应用中,这里从数据库或API获取产品列表
  const products = [
    { id: '1', name: '笔记本电脑' },
    { id: '2', name: '智能手机' },
    { id: '3', name: '平板电脑' },
  ];
  
  const paths = products.map(product => ({
    params: { id: product.id.toString() }
  }));
  
  return {
    paths,
    fallback: true // 或 false 或 'blocking'
  };
}

// 2. 获取页面数据
export async function getStaticProps({ params }) {
  const productId = params.id;
  
  // 模拟API调用
  const product = {
    id: productId,
    name: `产品${productId}`,
    description: `这是产品${productId}的详细描述`,
    price: 1000 + parseInt(productId) * 100,
  };
  
  return {
    props: {
      product
    },
    revalidate: 60 // ISR: 每60秒重新生成
  };
}

// 3. 页面组件
export default function ProductDetail({ product }) {
  const router = useRouter();
  
  // 如果页面正在生成,显示加载状态
  if (router.isFallback) {
    return <div>加载中...</div>;
  }
  
  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>价格: ¥{product.price}</p>
    </div>
  );
}

getServerSideProps(SSR)

javascript 复制代码
// pages/user/[userId].js
export async function getServerSideProps(context) {
  const { params, req, res, query } = context;
  const { userId } = params;
  
  // 获取用户信息(服务端执行)
  const userResponse = await fetch(`https://api.example.com/users/${userId}`);
  const user = await userResponse.json();
  
  // 获取用户订单(依赖用户信息)
  const ordersResponse = await fetch(`https://api.example.com/users/${userId}/orders`);
  const orders = await ordersResponse.json();
  
  return {
    props: {
      user,
      orders,
      timestamp: new Date().toISOString()
    }
  };
}

export default function UserProfile({ user, orders, timestamp }) {
  return (
    <div>
      <h1>{user.name} 的个人资料</h1>
      <p>邮箱: {user.email}</p>
      <p>注册时间: {user.createdAt}</p>
      <h2>订单列表</h2>
      <ul>
        {orders.map(order => (
          <li key={order.id}>
            订单 #{order.id} - ¥{order.amount}
          </li>
        ))}
      </ul>
      <p>页面生成时间: {timestamp}</p>
    </div>
  );
}

4.2 路由查询参数处理

javascript 复制代码
// pages/search/index.js
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

export default function SearchPage() {
  const router = useRouter();
  const { query, category, sort } = router.query;
  const [results, setResults] = useState([]);
  
  // 获取搜索结果
  useEffect(() => {
    if (query) {
      fetchResults(query, category, sort);
    }
  }, [query, category, sort]);
  
  const fetchResults = async (query, category, sort) => {
    // 构建搜索URL
    const params = new URLSearchParams();
    if (query) params.append('q', query);
    if (category) params.append('category', category);
    if (sort) params.append('sort', sort);
    
    const response = await fetch(`/api/search?${params}`);
    const data = await response.json();
    setResults(data);
  };
  
  const handleSearch = (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    const searchQuery = formData.get('query');
    
    // 更新URL,触发路由变化
    router.push({
      pathname: '/search',
      query: { query: searchQuery }
    });
  };
  
  return (
    <div>
      <form onSubmit={handleSearch}>
        <input 
          name="query" 
          defaultValue={query || ''} 
          placeholder="搜索..." 
        />
        <button type="submit">搜索</button>
      </form>
      
      <div>
        <h2>搜索结果</h2>
        <ul>
          {results.map(result => (
            <li key={result.id}>{result.title}</li>
          ))}
        </ul>
      </div>
    </div>
  );
}

五、路由导航与链接

5.1 客户端导航

基础导航

javascript 复制代码
import Link from 'next/link';

export default function Navigation() {
  return (
    <nav>
      <ul style={{ display: 'flex', gap: '20px' }}>
        <li>
          <Link href="/">
            <a>首页</a>
          </Link>
        </li>
        <li>
          <Link href="/about">
            <a>关于</a>
          </Link>
        </li>
        <li>
          <Link href="/products">
            <a>产品</a>
          </Link>
        </li>
        <li>
          <Link href="/blog">
            <a>博客</a>
          </Link>
        </li>
      </ul>
    </nav>
  );
}

动态路由导航

javascript 复制代码
import Link from 'next/link';

export default function ProductList({ products }) {
  return (
    <div>
      <h1>产品列表</h1>
      <ul>
        {products.map(product => (
          <li key={product.id}>
            <Link href={`/products/${product.id}`}>
              <a>{product.name}</a>
            </Link>
            <br />
            <Link href={{
              pathname: '/products/[id]',
              query: { id: product.id }
            }}>
              <a>(另一种写法)</a>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

5.2 编程式导航

javascript 复制代码
import { useRouter } from 'next/router';
import { useState } from 'react';

export default function LoginPage() {
  const router = useRouter();
  const [loading, setLoading] = useState(false);
  
  const handleLogin = async () => {
    setLoading(true);
    
    // 模拟登录API调用
    setTimeout(() => {
      // 登录成功后重定向
      router.push('/dashboard');
    }, 1000);
  };
  
  const handleGoBack = () => {
    // 返回上一页
    router.back();
  };
  
  const handleReplace = () => {
    // 替换当前历史记录
    router.replace('/profile');
  };
  
  return (
    <div>
      <h1>登录页面</h1>
      <button onClick={handleLogin} disabled={loading}>
        {loading ? '登录中...' : '登录'}
      </button>
      <button onClick={handleGoBack}>返回</button>
      <button onClick={handleReplace}>替换到个人资料</button>
      
      {/* 监听路由变化 */}
      <p>当前路由: {router.pathname}</p>
    </div>
  );
}

5.3 路由事件监听

javascript 复制代码
import { useEffect } from 'react';
import { useRouter } from 'next/router';

export default function RouteTracker() {
  const router = useRouter();
  
  useEffect(() => {
    const handleRouteChangeStart = (url) => {
      console.log('路由开始变化:', url);
      // 显示加载指示器
    };
    
    const handleRouteChangeComplete = (url) => {
      console.log('路由变化完成:', url);
      // 隐藏加载指示器
    };
    
    const handleRouteChangeError = (err, url) => {
      console.error('路由变化错误:', err, '目标URL:', url);
    };
    
    // 添加事件监听器
    router.events.on('routeChangeStart', handleRouteChangeStart);
    router.events.on('routeChangeComplete', handleRouteChangeComplete);
    router.events.on('routeChangeError', handleRouteChangeError);
    
    // 清理事件监听器
    return () => {
      router.events.off('routeChangeStart', handleRouteChangeStart);
      router.events.off('routeChangeComplete', handleRouteChangeComplete);
      router.events.off('routeChangeError', handleRouteChangeError);
    };
  }, [router]);
  
  return (
    <div>
      <h1>路由跟踪器</h1>
      <p>打开控制台查看路由事件</p>
    </div>
  );
}

六、高级路由模式

6.1 并行路由和拦截路由

拦截路由(Next.js 13+ App Router)

javascript 复制代码
// app/@modal/default.js - 模态框的默认状态(不显示)
export default function Default() {
  return null;
}

// app/@modal/(.)login/page.js - 拦截登录页,以模态框形式显示
'use client';

import { useRouter } from 'next/navigation';
import LoginForm from '@/components/LoginForm';

export default function InterceptedLogin() {
  const router = useRouter();
  
  const handleClose = () => {
    router.back();
  };
  
  return (
    <div className="modal-overlay">
      <div className="modal-content">
        <button onClick={handleClose}>关闭</button>
        <LoginForm />
      </div>
    </div>
  );
}

// app/layout.js - 根布局
export default function RootLayout({ children, modal }) {
  return (
    <html>
      <body>
        {children}
        {modal}
      </body>
    </html>
  );
}

6.2 动态导入与路由分组

路由分组(组织相关路由)

复制代码
pages/
├── (auth)/
│   ├── login.js
│   └── register.js
├── (shop)/
│   ├── products/
│   └── cart/
└── (admin)/
    ├── dashboard/
    └── users/

动态导入组件

javascript 复制代码
// 使用 dynamic import 实现路由分割
import dynamic from 'next/dynamic';
import { Suspense } from 'react';

// 动态导入组件,按需加载
const HeavyComponent = dynamic(() => import('@/components/HeavyComponent'), {
  loading: () => <p>加载中...</p>,
  ssr: false, // 禁用服务端渲染
});

const MapComponent = dynamic(() => import('@/components/MapComponent'), {
  loading: () => <p>地图加载中...</p>,
  suspense: true,
});

export default function ComplexPage() {
  return (
    <div>
      <h1>复杂页面</h1>
      
      {/* 普通动态导入 */}
      <HeavyComponent />
      
      {/* 使用 Suspense 的动态导入 */}
      <Suspense fallback={<p>加载地图组件...</p>}>
        <MapComponent />
      </Suspense>
    </div>
  );
}

6.3 中间件与路由保护

路由中间件

javascript 复制代码
// middleware.js
import { NextResponse } from 'next/server';
import { verifyToken } from './lib/auth';

export async function middleware(request) {
  const token = request.cookies.get('auth-token');
  const { pathname } = request.nextUrl;
  
  // 保护需要认证的路由
  const protectedRoutes = ['/dashboard', '/profile', '/settings'];
  const isProtectedRoute = protectedRoutes.some(route => 
    pathname.startsWith(route)
  );
  
  if (isProtectedRoute && !token) {
    // 重定向到登录页
    const url = request.nextUrl.clone();
    url.pathname = '/login';
    url.searchParams.set('redirect', pathname);
    return NextResponse.redirect(url);
  }
  
  // 如果已登录,重定向登录页到首页
  if (pathname === '/login' && token) {
    return NextResponse.redirect(new URL('/', request.url));
  }
  
  // 添加自定义header
  const response = NextResponse.next();
  response.headers.set('x-custom-header', 'custom-value');
  
  return response;
}

// 配置中间件匹配规则
export const config = {
  matcher: [
    /*
     * 匹配所有请求路径,除了:
     * - api (API路由)
     * - _next/static (静态文件)
     * - _next/image (图片优化)
     * - favicon.ico (网站图标)
     * - public文件夹
     */
    '/((?!api|_next/static|_next/image|favicon.ico|public/).*)',
  ],
};

七、路由优化策略

7.1 预加载策略

javascript 复制代码
import Link from 'next/link';

export default function NavigationWithPrefetch() {
  return (
    <nav>
      <ul>
        <li>
          {/* 默认预加载(视口内链接) */}
          <Link href="/">
            <a>首页</a>
          </Link>
        </li>
        <li>
          {/* 禁用预加载 */}
          <Link href="/about" prefetch={false}>
            <a>关于</a>
          </Link>
        </li>
        <li>
          {/* 手动触发预加载 */}
          <Link href="/contact">
            <a 
              onMouseEnter={() => {
                // 手动预加载
                import('next/link').then(Link => {
                  // 预加载逻辑
                });
              }}
            >
              联系我们
            </a>
          </Link>
        </li>
      </ul>
    </nav>
  );
}

7.2 滚动恢复与保持

javascript 复制代码
// 自定义滚动行为
import { useEffect } from 'react';
import { useRouter } from 'next/router';

export default function ScrollRestoration() {
  const router = useRouter();
  
  useEffect(() => {
    const handleRouteChange = () => {
      // 保存当前滚动位置
      sessionStorage.setItem(
        `scrollPos:${router.asPath}`,
        JSON.stringify({ x: window.scrollX, y: window.scrollY })
      );
    };
    
    const restoreScrollPosition = () => {
      const scrollPos = sessionStorage.getItem(`scrollPos:${router.asPath}`);
      if (scrollPos) {
        const { x, y } = JSON.parse(scrollPos);
        window.scrollTo(x, y);
      }
    };
    
    router.events.on('routeChangeStart', handleRouteChange);
    router.events.on('routeChangeComplete', restoreScrollPosition);
    
    return () => {
      router.events.off('routeChangeStart', handleRouteChange);
      router.events.off('routeChangeComplete', restoreScrollPosition);
    };
  }, [router]);
  
  return null;
}

八、API 路由系统

8.1 基础API路由

javascript 复制代码
// pages/api/users.js
export default function handler(req, res) {
  const { method } = req;
  
  switch (method) {
    case 'GET':
      return handleGet(req, res);
    case 'POST':
      return handlePost(req, res);
    case 'PUT':
      return handlePut(req, res);
    case 'DELETE':
      return handleDelete(req, res);
    default:
      res.setHeader('Allow', ['GET', 'POST', 'PUT', 'DELETE']);
      res.status(405).end(`Method ${method} Not Allowed`);
  }
}

async function handleGet(req, res) {
  // 查询参数
  const { limit = 10, offset = 0 } = req.query;
  
  // 模拟数据库查询
  const users = Array.from({ length: 50 }, (_, i) => ({
    id: i + 1,
    name: `用户${i + 1}`,
    email: `user${i + 1}@example.com`,
  }));
  
  const paginatedUsers = users.slice(
    parseInt(offset),
    parseInt(offset) + parseInt(limit)
  );
  
  res.status(200).json({
    success: true,
    data: paginatedUsers,
    pagination: {
      total: users.length,
      limit: parseInt(limit),
      offset: parseInt(offset),
    }
  });
}

async function handlePost(req, res) {
  const { name, email } = req.body;
  
  if (!name || !email) {
    return res.status(400).json({
      success: false,
      error: '缺少必要字段'
    });
  }
  
  // 模拟创建用户
  const newUser = {
    id: Date.now(),
    name,
    email,
    createdAt: new Date().toISOString(),
  };
  
  res.status(201).json({
    success: true,
    data: newUser,
  });
}

// 其他处理函数...

8.2 动态API路由

javascript 复制代码
// pages/api/users/[userId].js
import { createRouter } from 'next-connect';
import { getConnection } from '../../lib/database';

const router = createRouter();

// GET /api/users/:userId
router.get(async (req, res) => {
  const { userId } = req.query;
  const db = await getConnection();
  
  try {
    const user = await db.collection('users').findOne({ 
      _id: new ObjectId(userId) 
    });
    
    if (!user) {
      return res.status(404).json({ 
        success: false, 
        error: '用户不存在' 
      });
    }
    
    res.status(200).json({ success: true, data: user });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// PUT /api/users/:userId
router.put(async (req, res) => {
  const { userId } = req.query;
  const updateData = req.body;
  
  const db = await getConnection();
  
  try {
    const result = await db.collection('users').updateOne(
      { _id: new ObjectId(userId) },
      { $set: updateData }
    );
    
    if (result.matchedCount === 0) {
      return res.status(404).json({ 
        success: false, 
        error: '用户不存在' 
      });
    }
    
    const updatedUser = await db.collection('users').findOne({ 
      _id: new ObjectId(userId) 
    });
    
    res.status(200).json({ success: true, data: updatedUser });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// DELETE /api/users/:userId
router.delete(async (req, res) => {
  const { userId } = req.query;
  const db = await getConnection();
  
  try {
    const result = await db.collection('users').deleteOne({ 
      _id: new ObjectId(userId) 
    });
    
    if (result.deletedCount === 0) {
      return res.status(404).json({ 
        success: false, 
        error: '用户不存在' 
      });
    }
    
    res.status(204).end();
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

export default router.handler();

九、最佳实践与常见问题

9.1 路由组织结构最佳实践

复制代码
pages/
├── index.js                    # 首页
├── _app.js                     # 自定义App
├── _document.js                # 自定义Document
├── api/                        # API路由
│   ├── auth/                   # 认证相关
│   │   ├── login.js
│   │   ├── logout.js
│   │   └── register.js
│   ├── users/                  # 用户相关
│   │   ├── index.js
│   │   └── [id].js
│   └── products/               # 产品相关
│       ├── index.js
│       └── [id].js
├── auth/                       # 认证页面
│   ├── login.js
│   └── register.js
├── dashboard/                  # 仪表板(需要认证)
│   ├── index.js
│   ├── settings.js
│   └── analytics.js
├── products/                   # 产品页面
│   ├── index.js                # 产品列表
│   ├── [category]/            # 按分类
│   │   └── index.js
│   └── [id]/                  # 产品详情
│       └── index.js
├── blog/                       # 博客
│   ├── index.js                # 博客列表
│   ├── [year]/                # 按年份归档
│   │   ├── index.js
│   │   └── [month]/
│   │       └── index.js
│   └── [slug].js              # 博客文章
└── legal/                      # 法律页面
    ├── terms.js               # 服务条款
    └── privacy.js             # 隐私政策

9.2 常见问题与解决方案

问题1:路由404错误

javascript 复制代码
// 解决方案:自定义404页面
// pages/404.js
export default function Custom404() {
  return (
    <div style={{ textAlign: 'center', padding: '50px' }}>
      <h1>404 - 页面未找到</h1>
      <p>抱歉,您访问的页面不存在</p>
      <Link href="/">
        <a>返回首页</a>
      </Link>
    </div>
  );
}

问题2:动态路由参数类型错误

javascript 复制代码
// pages/products/[id].js
export async function getStaticPaths() {
  return {
    paths: [],
    fallback: 'blocking', // 使用blocking模式
  };
}

export async function getStaticProps({ params }) {
  const productId = parseInt(params.id);
  
  if (isNaN(productId)) {
    return {
      notFound: true, // 返回404
    };
  }
  
  // ... 获取数据
}

问题3:路由过渡动画

javascript 复制代码
// 使用Framer Motion实现路由过渡
import { motion, AnimatePresence } from 'framer-motion';
import { useRouter } from 'next/router';

export default function Layout({ children }) {
  const router = useRouter();
  
  return (
    <AnimatePresence mode="wait">
      <motion.div
        key={router.route}
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0, y: -20 }}
        transition={{ duration: 0.3 }}
      >
        {children}
      </motion.div>
    </AnimatePresence>
  );
}

十、性能优化与监控

10.1 路由性能监控

javascript 复制代码
// lib/performance.js
export function trackRoutePerformance() {
  if (typeof window !== 'undefined' && 'performance' in window) {
    const navigationTiming = performance.getEntriesByType('navigation')[0];
    
    const metrics = {
      dnsTime: navigationTiming.domainLookupEnd - navigationTiming.domainLookupStart,
      tcpTime: navigationTiming.connectEnd - navigationTiming.connectStart,
      requestTime: navigationTiming.responseEnd - navigationTiming.requestStart,
      domContentLoaded: navigationTiming.domContentLoadedEventEnd - navigationTiming.fetchStart,
      fullLoadTime: navigationTiming.loadEventEnd - navigationTiming.fetchStart,
    };
    
    // 发送到监控服务
    sendToAnalytics(metrics);
  }
}

// _app.js
import App from 'next/app';
import { trackRoutePerformance } from '../lib/performance';
import Router from 'next/router';

Router.events.on('routeChangeComplete', trackRoutePerformance);

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;

10.2 路由缓存策略

javascript 复制代码
// 自定义缓存策略
import { useEffect } from 'react';
import { useRouter } from 'next/router';

export default function RouteCacheManager() {
  const router = useRouter();
  
  useEffect(() => {
    // 预取重要路由
    const prefetchRoutes = ['/dashboard', '/profile', '/settings'];
    prefetchRoutes.forEach(route => {
      router.prefetch(route);
    });
    
    // 管理路由缓存
    const cache = new Map();
    
    const handleRouteChange = (url) => {
      // 缓存当前页面数据
      cache.set(router.asPath, {
        timestamp: Date.now(),
        scrollPosition: window.scrollY,
      });
      
      // 清理过期缓存(超过5分钟)
      const now = Date.now();
      for (const [key, value] of cache.entries()) {
        if (now - value.timestamp > 5 * 60 * 1000) {
          cache.delete(key);
        }
      }
    };
    
    router.events.on('routeChangeStart', handleRouteChange);
    
    return () => {
      router.events.off('routeChangeStart', handleRouteChange);
    };
  }, [router]);
  
  return null;
}

总结

Next.js 的文件系统路由是一个强大而灵活的特性,它通过简单的文件结构提供了完整的路由解决方案。关键要点包括:

  1. 约定优于配置:通过文件系统自动生成路由,减少样板代码
  2. 多种路由类型:支持静态路由、动态路由、可选路由等
  3. 预渲染支持:无缝集成 SSG 和 SSR 数据获取
  4. API 路由集成:前后端同构开发体验
  5. 性能优化:自动代码分割、预加载、路由过渡

通过合理利用文件系统路由的特性,可以构建出高性能、可维护的现代 Web 应用。无论是简单的静态网站还是复杂的企业级应用,Next.js 的路由系统都能提供合适的解决方案。

相关推荐
炬火初现2 小时前
C++17特性(3)
开发语言·c++
煤炭里de黑猫2 小时前
Python 爬虫进阶:利用 Frida 逆向移动端 App API 以实现高效数据采集
开发语言·爬虫·python
草莓熊Lotso2 小时前
Linux 进程创建与终止全解析:fork 原理 + 退出机制实战
linux·运维·服务器·开发语言·汇编·c++·人工智能
枫叶丹42 小时前
【Qt开发】Qt系统(九)-> Qt TCP Socket
c语言·开发语言·网络·c++·qt·tcp/ip
holeer2 小时前
14步入门Vue|cn.vuejs.org教程学习笔记
前端·javascript·vue.js·笔记·前端框架·教程·入门
007php0074 小时前
PHP与Java项目在服务器上的对接准备与过程
java·服务器·开发语言·分布式·面试·职场和发展·php
Evand J5 小时前
【MATLAB程序,一维非线性EKF与RTS】MATLAB,用于一维的位移与速度滤波和RTS平滑/高精度定位,带滤波前后的误差对比
开发语言·matlab·卡尔曼滤波·rts平滑·正向滤波
Web极客码5 小时前
WordPress 6.8有哪些新特性
前端·javascript·html
火云洞红孩儿10 小时前
告别界面孤岛:PyMe如何用一站式流程重塑Python GUI开发?
开发语言·python