Skip to content

Pages - 页面目录

Nuxt 提供了一种基于文件的路由,可以使用Vue Router在 web 应用程序中创建路由。

pages目录是可选的,这意味着如果只使用app.vue就不会包含vue-router,从而减少你的应用程序的包的大小。

使用

页面是Vue组件,可以具有.vue.js.jsx.ts.tsx扩展名:

~/pages/index.vue

<template>
  <h1>Index page</h1>
</template>

~/pages/index.ts

// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
  render () {
    return h('h1', 'Index page')
  }
})

~/pages/index.tsx

// https://v3.nuxtjs.org/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
  render () {
    return <h1>Index page</h1>
  }
})

pages/index.vue文件映射应用程序的路由是:/

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

app.vue

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

页面必须具有单个根元素,以允许页面之间的路由转换。(HTML注释也被视为元素。)

这意味着,当路由被服务器渲染或静态生成时,将能够正确地看到它的内容,但当在客户端导航时向该路由导航时,路由之间的转换将失败,将看到该路由不会被渲染。

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

~/pages/working.vue

<template>
  <div>
    <!-- 这个页面只有一个单一的根元素 -->
    Page content
  </div>
</template>

~/pages/bad-1.vue

<template>
  <!-- 由于本注释,当客户端导航期间路由更改时,将不会呈现此页面,因为注释也是被视为元素 -->
  <div>Page content</div>
</template>

~/pages/bad-2.vue

<template>
  <div>This page</div>
  <div>有多个跟元素</div>
  <div>在客户端导航期间路线更改时不会被渲染</div>
</template>

动态路由

如果把任何东西放在[]内,它将变成一个动态路径参数。可以混合和匹配多个参数,甚至在一个文件名或目录内的非动态文本。

如果想让一个参数是可选的,必须用[[]]把它括起来,例如:~/pages/[[slug]]/index.vue~/pages/[[slug]].vue将同时匹配//test

示例:

-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

鉴于上面的例子,你可以通过$route对象在你的组件中访问group/id

~/pages/users-[group]/[id].vue

<template>
  <p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>

导航到/users-admins/123后呈现的效果:

<p>admins - 123</p>

如果想使用Composition API访问路由,有一个全局的useRoute函数,它将允许访问路由,就像选项 API 中的this.$route一样。

<script setup>
const route = useRoute()

if (route.params.group === 'admins' && !route.params.id) {
  console.log('Warning! Make sure user is authenticated!')
}
</script>

Catch-all Route 通用路由

如果需要一个 Catch-all Route 通用路由,你可以用一个名为[...slug].vue的文件来创建它。这将匹配该路径下的所有路由。

~/pages/[...slug].vue

<template>
  <p>{{ $route.params.slug }}</p>
</template>

导航到/hello/world后呈现的效果:

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

Nuxt 还支持自定义~/pages/404.vue文件,该文件将处理所有不匹配的路由(并设置 404 错误代码)。

Nested Routes 嵌套路由

可以使用<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>I am the parent view</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>

子路由 Keys

如果希望对<NuxtPage>组件重新渲染的时候有更多的控制(例如,transitions),你可以通过pageKey属性传递一个字符串或函数,或者可以通过definePageMeta定义键值:

~/pages/parent.vue

<template>
  <div>
    <h1>I am the parent view</h1>
    <NuxtPage :page-key="someKey" />
  </div>
</template>

~/pages/child.vue

<script setup>
definePageMeta({
  key: route => route.fullPath
})
</script>

详细示例参考:https://v3.nuxtjs.org/examples/routing/pages

Page Metadata 页面元数据

想为应用程序中的每个路由定义元数据。可以使用definePageMeta宏来做到这一点,它在<script><script setup>中都可以使用:

<script setup>
definePageMeta({
  title: 'My home page'
})
</script>

然后,可以通过路由在应用程序的其它地方访问route.meta对象。

<script setup>
const route = useRoute()

console.log(route.meta.title) // My home page
</script>

如果使用嵌套路由,所有这些路由的页面元数据将被合并到一个对象中。有关路由元的更多信息,请参阅vue router文档

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

<script setup>
import { someData } from '~/utils/example'

const title = ref('')

definePageMeta({
  title,  // 这里不能引用组件定义的值,这将产生一个错误
  someData
})
</script>

特殊的元数据

当然,可以自定义元数据,供自己在整个应用程序中使用。但是用definePageMeta定义的一些元数据有一个特殊的目的。

keepalive

如果在definePageMeta中设置了keepalive: true,Nuxt 会自动将页面包装成Vue <KeepAlive>组件。例如,在一个拥有动态子路由的父路由中,如果想在路由变化中保留页面状态。也可以设置传递给<KeepAlive>的 props(见这里的完整列表)。

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

key

见上文

layout

可以定义用于渲染路由的布局。这可以是false(禁用任何布局),也可以是一个字符串或一个ref/computed更多关于布局的信息

middleware

可以定义中间件,在加载这个页面之前应用。它将与任何匹配的父/子路由中使用的所有其他中间件合并。它可以是一个字符串,一个函数(一个匿名/精简的中间件函数,遵循全局的before guard模式),或一个字符串/函数的数组。更多关于命名的中间件.

layoutTransitionpageTransition

你可以为包裹页面和布局的<transition>组件定义过渡属性,或者通过false来禁用该路由的<transition>包装器。你可以在这里看到一个可以传递的选项列表,或者阅读更多关于过渡如何工作的信息。

你可以在nuxt.config中为这些属性设置默认值。

alias

可以定义页面别名。它们允许从不同的路径访问同一页面。它可以是字符串,也可以是vue router文档中定义的字符串数组。

自定义元数据

如果为页面添加自定义元数据,可能希望以类型安全的方式添加。可以增加definePageMeta接受的对象类型:

// index.d.ts

declare module '#app' {
  interface PageMeta {
    pageType?: string
  }
}

// 在扩展类型时,确保导入/导出某些内容总是很重要的
export {}

要在应用程序的页面之间导航,应使用<NuxtLink>组件。此组件包含在 Nuxt 中,因此不必像导入其他组件那样导入它。

一个导航到pages目录中index.vue页面的示例:

<template>
  <NuxtLink to="/">Home page</NuxtLink>
</template>

了解更多关于<NuxtLink>使用。

路由选项

可以设置默认的vue路由选项。

historyroutes选项将始终被 Nuxt 覆盖。

使用app/router.options

这是指定router.options的推荐方式。

~/app/router.options.ts

import type { RouterConfig } from '@nuxt/schema'

// https://router.vuejs.org/api/interfaces/routeroptions.html
export default <RouterConfig>{
}

使用nuxt.config

只有 JSON 可序列化的选项是可配置的:

  • linkActiveClass
  • linkExactActiveClass
  • end
  • sensitive
  • strict
// nuxt.config.ts

export default defineNuxtConfig({
  router: {
    // https://router.vuejs.org/api/interfaces/routeroptions.html
    options: {}
  }
})

编程式导航

Nuxt3 允许通过navigateTo()方法进行编程式导航。该方法将能够在应用程序中以编程方式为用户导航。这对于接受用户的输入并在应用程序中动态地导航他们是非常好的。

TIP

确保navigateTo是通过await或者在函数中return其结果。

如:

<script setup>
const router = useRouter();
const name = ref('');
const type = ref(1);

function navigate(){
  return navigateTo({
    path: '/search',
    query: {
      name: name.value,
      type: type.value
    }
  })
}
</script>