pages

Nuxt 提供了基于文件的路由功能,可以在你的 web 应用中创建路由。
为了减少应用程序的捆绑包大小,该目录是可选的,这意味着如果您只使用 app.vue,将不会包含 vue-router。若要强制页面系统,请在 nuxt.config 中设置 pages: true,或拥有 app/router.options.ts

使用

页面是 Vue 组件,可以有 Nuxt 支持的任何有效扩展名(默认为 .vue.js.jsx.mjs.ts.tsx)。

Nuxt 将自动为你的 ~/pages/ 目录中的每个页面创建一个路由。

<template>
  <h1>Index 页面</h1>
</template>

pages/index.vue 文件将被映射到你的应用程序的 / 路由。

如果你使用 ~/pages/app.vue,确保使用 <NuxtPage/> 组件来显示当前页面:

app.vue
<template>
  <div>
    <!-- Markup shared across all pages, ex: NavBar -->
    <NuxtPage />
  </div>
</template>

页面必须有一个根元素,以允许路由过渡。HTML 注释也被认为是元素。

这意味着当路由被服务器渲染,或者静态生成时,你将能够正确地看到其内容,但是当你在客户端导航时,如果出现多个根元素,路由将不会被渲染。

以下是一些示例,以说明只有一个根元素的页面是什么样子的:

<template>
  <div>
    <!-- This page correctly has only one single root element -->
    页面内容
  </div>
</template>

动态路由

如果在你放置任何内容在方括号中,它将变成一个动态路由参数。你可以在文件名或目录中混合和匹配多个参数和非动态文本。

如果你希望一个参数是_可选的_,你必须将它用双方括号括起来,例如 ~/pages/[[slug]]/index.vue~/pages/[[slug]].vue 将会匹配 //test

目录结构
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

给上面的例子,你可以在你的组件通过 $route 对象访问组 /ID:

pages/users-[group]/[id].vue
<template>
  <p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>

导航到 /users-admins/123 将渲染:

<p>admins - 123</p>

如果你想用组合 API 访问路由,有一个全局的 useRoute 函数允许你访问路由就像在选项 API 中 this.$route

<script setup lang="ts">
const 
route
=
useRoute
()
if (
route
.
params
.
group
=== 'admins' && !
route
.
params
.
id
) {
console
.
log
('Warning! Make sure user is authenticated!')
} </script>
命名的父路由将优先于嵌套的动态路由。对于 /foo/hello 路由,~/pages/foo.vue 将优先于 ~/pages/foo/[slug].vue
使用 ~/pages/foo/index.vue~/pages/foo/[slug].vue 来匹配 /foo/foo/hello 不同的页面。

捕获所有路由

如果你需要一个捕获所有路由,你通过创建一个名为 [...slug].vue 的文件。这将匹配_所有_该路径下的路由。

pages/[...slug].vue
<template>
  <p>{{ $route.params.slug }}</p>
</template>

导航到 /hello/world 将渲染:

<p>["hello", "world"]</p>

嵌套路由

你可以使用 <NuxtPage><NuxtPage> 组件内部显示嵌套路由

示例:

目录结构
-| pages/
---| parent/
-----| child.vue
---| parent.vue

这个文件树将产生这些路由:

[
  {
    path: '/parent',
    component: '~/pages/parent.vue',
    name: 'parent',
    children: [
      {
        path: 'child',
        component: '~/pages/parent/child.vue',
        name: 'parent-child'
      }
    ]
  }
]

要显示 child.vue 组件,你必须在 pages/parent.vue 中插入 <NuxtPage> 组件:

pages/parent.vue
<template>
  <div>
    <h1>我是父视图</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>
pages/parent/child.vue
<script setup lang="ts">
const props = defineProps(['foobar'])

console.log(props.foobar)
</script>

子路由键

如果你想控制何时重新渲染 <NuxtPage> 组件(例如,为过渡),你可以通过 pageKey 属性传递一个字符串或函数,或者你可以在 definePageMeta 中定义一个 key 值:

pages/parent.vue
<template>
  <div>
    <h1>我是父视图</h1>
    <NuxtPage :page-key="route => route.fullPath" />
  </div>
</template>

或者可以替代:

pages/parent/child.vue
<script setup lang="ts">
definePageMeta
({
key
:
route
=>
route
.fullPath
}) </script>
Read and edit a live example in Docs > Examples > Routing > Pages.

路由组

在某些情况下,您可能希望以不影响基于文件的路由的方式将一组路由分组在一起。为此,您可以将文件放入用括号包装的文件夹中 - ()

例如:

Directory structure
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue

这将在您的应用程序中生成 //about/contact 页面。 marketing 组将在您的 URL 结构中被忽略。

页面元数据

你可能需要在你的应用中为每个路由定义元数据。你可以在 <script><script setup> 中使用 definePageMeta 宏来实现这一点:

<script setup lang="ts">
definePageMeta
({
title
: '我的主页面'
}) </script>

这个数据可以从 route.meta 对象在整个应用中访问。

<script setup lang="ts">
const 
route
=
useRoute
()
console
.
log
(
route
.
meta
.
title
) // 我的主页面
</script>

如果你使用嵌套路由,那么页面的元数据将从所有匹配的父/子路由合并成一个单独的对象。有关更多关于路由元数据的详情,请参阅 Vue Router 文档

就像 defineEmitsdefineProps(见 Vue 文档),definePageMeta 是一个编译宏。它将被编译掉,因此你无法在组件中引用它。相反,传递给它的元数据将被从组件中提升出来。因此,页面元对象不能引用组件(或组件上定义的值)。但是,它可以引用导入的绑定。

<script setup lang="ts">
import { someData } from '~/utils/example'

const title = ref('')

definePageMeta({
  title,  // 这将创建一个错误
  someData
})
</script>

特殊的元数据

当然,你欢迎定义自己的元数据来在你的应用中使用。但是一些通过 definePageMeta 定义的元数据有特定的用途:

alias

你可以定义页面的别名。它们允许你从不同的路径访问同一页面。它可以是字符串或字符串数组,如这里在 Vue Router 文档中定义。

keepalive

如果你在 definePageMeta 中设置了 keepalive: true,Nuxt 将自动将你的页面包裹在 Vue <KeepAlive> 组件中。这可能在你想要在路由变化时保留页面状态时有用。

当你的目标是保留父路由的状态时,可以使用这个语法:<NuxtPage keepalive />。你也可以设置 <KeepAlive> 的 props(参见这里或阅读更多关于如何过渡

你可以在 nuxt.config 中设置这个属性的默认值

key

请参阅上文

layout

你可以定义用于渲染路由的布局。这可以是 false(以禁用任何布局),一个字符串或一个 ref/computed,如果你想让它以某种方式是可响应的。更多关于布局

layoutTransitionpageTransition

你可以为包裹页面的 <transition> 组件定义转换属性,或通过传递 false 来禁用该页面的 <transition> 包装器。你可以在这里看到可以传递的选项或阅读更多关于转换的工作方式

你可以在 nuxt.config 中设置默认值

middleware

你可以定义中间件,在加载这个页面之前应用它。它将和任何匹配的父/子路由中使用的其他中间件合并。它可以是字符串,函数(遵循全局前置守卫模式的匿名/内联中间件函数),或字符串/函数数组。更多关于命名中间件

name

你可以定义这个页面路由的名字。

path

你可以定义一个路径匹配器,如果你有一个更复杂的模式,不能用文件名表达。请参见 Vue Router 文档了解更多信息。

props

允许将路由 params 作为传递给页面组件的 props 进行访问。有关更多信息,请参见 vue-router 文档

类型化的自定义元数据

如果你为你的页面添加了自定义元数据,你可能会希望在类型安全的方式下这样做。可以通过扩展 accepted object 的类型来增强 definePageMeta 接受的类型:

index.d.ts
declare module '#app' {
  interface PageMeta {
    pageType?: string
  }
}

// 始终确保在扩展类型时导入/导出一些东西
export {}

导航

要导航你的应用页面,你应该使用 <NuxtLink> 组件。

这个组件 Nuxt 直接提供,因此你不需要像其他组件那样导入它。

一个简单的链接到你的 pages 文件夹中的 index.vue 页面:

<template>
  <NuxtLink to="/">主页面</NuxtLink>
</template>
了解更多关于 <NuxtLink> 的使用。

程序化导航

Nuxt 允许通过 navigateTo() 实用工具方法进行程序化导航。使用这个实用工具方法,你将能够以编程方式在你的应用中导航用户。这很适合从用户那里获取输入并动态地在整个应用中引导他们。在这个例子中,我们有一个简单的叫做 navigate() 的方法,在用户提交搜索表单时被调用。

请确保始终在 navigateTo 上使用 await 或通过从函数返回其结果进行链接。
<script setup lang="ts">
const 
name
=
ref
('');
const
type
=
ref
(1);
function
navigate
(){
return
navigateTo
({
path
: '/search',
query
: {
name
:
name
.
value
,
type
:
type
.value
} }) } </script>

仅客户端页面

你可以定义一个页面为仅客户端,通过给它一个 .client.vue 后缀。这个页面的任何内容都不会在服务器上渲染。

仅服务器页面

你可以定义一个页面为仅服务器,通过给它一个 .server.vue 后缀。当你可以通过客户端导航访问该页面时,它将被渲染为服务器组件,这意味着渲染页面所需的代码不会包含在你的客户端捆绑包中。

仅服务器页面必须有一个单一的根元素。(HTML 注释也被认为是元素。)

自定义路由

随着你的应用越来越大,越来越复杂,你的路由可能需要更多的灵活性。因此,Nuxt直接暴露了路由、路由选项和路由选项,以便以不同的方式进行自定义。

Read more in Docs > Guide > Recipes > Custom Routing.

多个页面目录

默认情况下,你所有的页面应该在一个根项目中的 pages 目录中。

然而,你可以使用 Nuxt Layers 来创建你的应用页面的分组:

目录结构
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
some-app/nuxt.config.ts
// some-app/nuxt.config.ts
export default 
defineNuxtConfig
({
})
nuxt.config.ts
export default 
defineNuxtConfig
({
extends
: ['./some-app'],
})
Read more in Docs > Guide > Going Further > Layers.