分为 App Router 和 Pages Router,目前主要用 App Router

路由

路由结构不是通过一般的 router.js 来定义,而是直接通过【文件夹】的组织形式定义的,app 目录下存放所有的路由文件。

文件夹下面有 page.tsx 文件,路由才可公开访问。而且,即使一个路由被设置为公开访问,也只会有 page.tsx 返回的内容发送给客户端。

文件路径对应的 URLNotes
app/page.tsx/根路由
app/blog/page.tsx/blog页面路由
app/blog/authors/page.tsx/blog/authors页面路由

动态路由

使用方括号 [] 作为文件名:使用 [segment] 表示单个参数, [...segment] 表示捕获所有, [[...segment]] 表示可选捕获所有。

文件路径可能对应的 URL
app/blog/[slug]/page.tsx/blog/post
---
app/blog/[...slug]/page.tsx/blog/post
/blog/my-blog/post
---
app/blog/[[...slug]]/page.tsx/blog
/blog/post
/blog/my-blog/post

分组

使用小括号 () 作为文件名:不会出现在 URL 里,如 app/(my-blog)/blog/page.tsx 对应的还是 /blog。适合用来组织一批类似的路由文件夹

私有文件夹

在文件夹名前加上下划线:_folderName,表示该文件夹是一个私有实现细节,将此文件夹及其所有子文件夹排除在路由之外

路由跳转

1.使用内置组件

使用 <Link> 组件在路由之间进行导航:

import Link from 'next/link'
 
export default async function Post({ post }) {
  const posts = await getPosts()
 
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

2.使用 useRouter

import { useRouter } from 'next/navigation'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}
  • router.push(href: string, { scroll: boolean }):进行路由跳转,向浏览器的历史记录堆栈添加一个新记录
  • router.replace(href: string, { scroll: boolean }):进行路由跳转,但不向浏览器的历史记录堆栈添加新记录
  • router.refresh() : 刷新当前路由
  • router.prefetch(href: string, options?: { onInvalidate?: () => void }) : 预取提供的路由以实现更快的客户端过渡
  • router.back() : 在浏览器的历史记录栈中导航回上一个路由
  • router.forward() : 在浏览器的历史记录栈中导航到下一个页面

默认情况下,当导航到新路由时,Next.js 会自动滚动到页面顶部。使用 scroll: false 阻止滚动

获取路由信息

useParams

当前 URL 动态路由中的参数

import { useParams } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const params = useParams<{ tag: string; item: string }>()
 
  // Route -> /shop/[tag]/[item]
  // URL -> /shop/shoes/nike-air-max-97
  // `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
  console.log(params)
 
  return '...'
}
RouteURLuseParams()
app/shop/page.js/shop{}
app/shop/[slug]/page.js/shop/1{ slug: '1' }
app/shop/[tag]/[item]/page.js/shop/1/2{ tag: '1', item: '2' }
app/shop/[...slug]/page.js/shop/1/2{ slug: ['1', '2'] }

usePathname

读取当前 URL 的路径名

import { usePathname } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const pathname = usePathname()
  return <p>Current pathname: {pathname}</p>
}
URL返回值
/'/'
/dashboard'/dashboard'
/dashboard?v=2'/dashboard'
/blog/hello-world'/blog/hello-world'

useSearchParams

读取当前 URL 的查询字符串

import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>
}

useSearchParams 返回 URLSearchParams 接口的只读版本,有着共同的实用方法