pages
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/>
组件来显示当前页面:
<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:
<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
的文件。这将匹配_所有_该路径下的路由。
<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>
组件:
<template>
<div>
<h1>我是父视图</h1>
<NuxtPage :foobar="123" />
</div>
</template>
<script setup lang="ts">
const props = defineProps(['foobar'])
console.log(props.foobar)
</script>
子路由键
如果你想控制何时重新渲染 <NuxtPage>
组件(例如,为过渡),你可以通过 pageKey
属性传递一个字符串或函数,或者你可以在 definePageMeta
中定义一个 key
值:
<template>
<div>
<h1>我是父视图</h1>
<NuxtPage :page-key="route => route.fullPath" />
</div>
</template>
或者可以替代:
<script setup lang="ts">
definePageMeta({
key: route => route.fullPath
})
</script>
路由组
在某些情况下,您可能希望以不影响基于文件的路由的方式将一组路由分组在一起。为此,您可以将文件放入用括号包装的文件夹中 - (
和 )
。
例如:
-| 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 文档。
就像 defineEmits
或 defineProps
(见 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(参见这里或阅读更多关于如何过渡。
key
layout
你可以定义用于渲染路由的布局。这可以是 false
(以禁用任何布局),一个字符串或一个 ref/computed,如果你想让它以某种方式是可响应的。更多关于布局。
layoutTransition
和 pageTransition
你可以为包裹页面的 <transition>
组件定义转换属性,或通过传递 false
来禁用该页面的 <transition>
包装器。你可以在这里看到可以传递的选项或阅读更多关于转换的工作方式。
middleware
你可以定义中间件,在加载这个页面之前应用它。它将和任何匹配的父/子路由中使用的其他中间件合并。它可以是字符串,函数(遵循全局前置守卫模式的匿名/内联中间件函数),或字符串/函数数组。更多关于命名中间件。
name
你可以定义这个页面路由的名字。
path
你可以定义一个路径匹配器,如果你有一个更复杂的模式,不能用文件名表达。请参见 Vue Router 文档了解更多信息。
props
允许将路由 params
作为传递给页面组件的 props 进行访问。有关更多信息,请参见 vue-router 文档。
类型化的自定义元数据
如果你为你的页面添加了自定义元数据,你可能会希望在类型安全的方式下这样做。可以通过扩展 accepted object
的类型来增强 definePageMeta
接受的类型:
declare module '#app' {
interface PageMeta {
pageType?: string
}
}
// 始终确保在扩展类型时导入/导出一些东西
export {}
导航
要导航你的应用页面,你应该使用 <NuxtLink>
组件。
这个组件 Nuxt 直接提供,因此你不需要像其他组件那样导入它。
一个简单的链接到你的 pages
文件夹中的 index.vue
页面:
<template>
<NuxtLink to="/">主页面</NuxtLink>
</template>
程序化导航
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
后缀。当你可以通过客户端导航访问该页面时,它将被渲染为服务器组件,这意味着渲染页面所需的代码不会包含在你的客户端捆绑包中。
自定义路由
随着你的应用越来越大,越来越复杂,你的路由可能需要更多的灵活性。因此,Nuxt直接暴露了路由、路由选项和路由选项,以便以不同的方式进行自定义。
多个页面目录
默认情况下,你所有的页面应该在一个根项目中的 pages
目录中。
然而,你可以使用 Nuxt Layers 来创建你的应用页面的分组:
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
export default defineNuxtConfig({
extends: ['./some-app'],
})