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>首页</h1>
</template>
// https://vue.zhcndoc.com/guide/extras/render-function.html
export default defineComponent({
render () {
return h('h1', '首页')
}
})
// https://nuxt.com/docs/examples/advanced/jsx
// https://vue.zhcndoc.com/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
render () {
return <h1>首页</h1>
}
})
pages/index.vue
文件将映射到您应用程序的 /
路由。
如果您正在使用 app.vue
,请确保使用 <NuxtPage/>
组件来显示当前页面:
<template>
<div>
<!-- 在所有页面中共享的标记,例如:导航栏 -->
<NuxtPage />
</div>
</template>
页面 必须具有单一根元素 以允许 路由过渡 之间的页面切换。HTML 注释也被视为元素。
这意味着当路由在服务器上渲染或静态生成时,您将能够正确看到其内容,但当您在客户端导航到该路由时,路由之间的过渡将失败,您将看到该路由未被渲染。
以下是一些示例,以说明具有单一根元素的页面是什么样的:
<template>
<div>
<!-- 此页面正确地只有一个根元素 -->
页面内容
</div>
</template>
<template>
<!-- 此页面在客户端导航时路由更改时将不会渲染,因为这个注释 -->
<div>页面内容</div>
</template>
<template>
<div>这个页面</div>
<div>有多个根元素</div>
<div>并且在客户端导航时路由更改时不会渲染</div>
</template>
动态路由
如果在方括号内放置任何内容,它将变成一个 动态路由 参数。您可以在文件名或目录内混合匹配多个参数甚至非动态文本。
如果您希望一个参数为 可选,必须将其用双方括号括起来——例如,~/pages/[[slug]]/index.vue
或 ~/pages/[[slug]].vue
将同时匹配 /
和 /test
。
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
根据上面的例子,您可以通过 $route
对象在组件中访问 group/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('警告!确保用户已经认证!')
}
</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>
显示 嵌套路由。
示例:
-| 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 结构。
页面元数据
您可能希望为应用程序中的每个路由定义元数据。您可以使用 definePageMeta
宏做到这一点,它在 <script>
和 <script setup>
中都有效:
<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'
function validateIdParam(route) {
return route.params.id && !isNaN(Number(route.params.id))
}
const title = ref('')
definePageMeta({
validate: validateIdParam,
someData,
title, // 不要这样做,ref 将被提升出组件
})
</script>
特殊元数据
当然,您可以定义自己的元数据以供应用程序的使用。但是,用 definePageMeta
定义的一些元数据有特定的目的:
alias
您可以定义页面别名。它们允许您从不同的路径访问同一页面。它可以是一个字符串或字符串数组,如 vue-router 文档 中所定义的。
keepalive
如果您在 definePageMeta
中设置 keepalive: true
,Nuxt 将自动将您的页面包装在 Vue <KeepAlive>
组件 中。例如,在具有动态子路由的父路由中,如果您希望在路由更改之间保留页面状态,则可能会有用。
当您希望为父路由保留状态时,请使用以下语法:<NuxtPage keepalive />
。您还可以设置传递给 <KeepAlive>
的属性(请查看完整列表 这里)。
您可以在您的 nuxt.config
中为此属性设置默认值 (/docs/api/nuxt-config#keepalive)。
key
见上文。
layout
您可以定义用于渲染路由的布局。这可以是 false
(禁用任何布局)、字符串或 ref/计算属性,如果您希望它以某种方式响应式。有关布局的更多信息。
layoutTransition
和 pageTransition
您可以定义包裹您的页面和布局的 <transition>
组件的过渡属性,或者传递 false
以禁用该路由的 <transition>
包装程序。您可以查看可以传递的选项列表 这里 或者阅读 关于过渡如何工作的更多信息。
您可以在您的 nuxt.config
中为这些属性设置默认值 (/docs/api/nuxt-config#layouttransition)。
middleware
您可以定义在加载此页面之前应用的中间件。它将与任何匹配的父子路由中使用的所有其他中间件合并。它可以是一个字符串、一个函数(遵循 全局前置守卫模式 的匿名/内联中间件函数),或者一个字符串/函数数组。有关命名中间件的更多信息。
name
您可以为该页面的路由定义一个名称。
path
如果您有比文件名更复杂的模式,您可以定义路径匹配器。有关更多信息,请参见 vue-router 文档。
props
允许将路由 params
作为传递给页面组件的 props 进行访问。有关更多信息,请参见 vue-router 文档。
自定义元数据的类型
如果您为您的页面添加自定义元数据,您可能希望以类型安全的方式进行。这可以通过增强 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
后缀来定义一个页面为 仅服务器。虽然您能够通过由 vue-router
控制的客户端导航访问该页面,但它将自动使用服务器组件进行渲染,这意味着渲染页面所需的代码将不在您的客户端捆绑包中。
仅服务器页面必须具有单一根元素。(HTML 注释也被视为元素。)
自定义路由
随着您的应用程序变得更大、更复杂,您的路由可能需要更多的灵活性。为此,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'],
})