首页 / Nuxt 4 入门教程 / 页面元数据

Nuxt 4 入门教程

页面元数据

本教程共 50 篇 · 第 14 篇 · 更新于 2026-08-08 · 约 5 分钟阅读

NuxtNuxt4definePageMeta页面元数据keepalive

本节目标:学会用 definePageMeta 给每个页面设置专属元数据,理解 keepalive 如何保持页面状态。

14-1

每个页面除了「显示什么内容」,往往还需要一些「关于这个页面本身的说明」:它用哪个布局、进入前要跑什么中间件、要不要保持状态、标题叫什么。这些说明就叫页面元数据(page metadata)。

在 Nuxt 里,设置元数据统一用 definePageMeta 这个编译宏(compiler macro)。它看起来像一个函数,但和普通函数不同——它会在编译阶段被处理掉,不会出现在最终的运行时代码里。所以你不能把它当普通函数去调用或引用,只能在 <script setup> 顶层直接使用。

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

宏(macro)是 Vue 单文件组件编译期的一种特殊写法,比如 definePropsdefineEmits 也是宏。definePageMeta 同理:它只是给编译器看的「标记」,会被直接提升到组件外面变成路由信息。因此,你在 definePageMeta 里不能引用组件内的响应式数据或会触发副作用的函数,只能引用导入的绑定和本地定义的纯函数。

14-2

你写在 definePageMeta 里的自定义字段,会被挂到路由对象的 meta 上。在任意组件里,用 useRoute() 就能读出来:

<script setup lang="ts">
const route = useRoute()

console.log(route.meta.title) // 输出:我的首页
</script>

这一招在你做「根据页面切换全局标题」「按页面分组做权限判断」之类需求时非常有用。比如你想在导航栏里显示当前页面标题,就可以从 route.meta 里取。

Tip

想要类型安全的话,可以扩展 PageMeta 接口。新建一个 .d.ts 文件(例如项目根目录的 index.d.ts),写上 declare module '#app' { interface PageMeta { pageType?: string } },之后 definePageMeta 就能补全并校验你自定义的字段了。

14-3

keepalivedefinePageMeta 里一个很实用的特殊字段。当设为 true 时,Nuxt 会用 Vue 的 <KeepAlive> 组件把页面包起来。效果是:你从这个页面跳走再跳回来,页面之前的运行状态(比如输入框里填的字、滚动位置、组件里的局部变量)会被保留,而不是重新从零渲染。

<script setup lang="ts">
definePageMeta({
  keepalive: true,
})
</script>

这在「父路由带多个动态子路由」的场景尤其好用。举个例子,左侧是一列文章列表,右侧是文章内容。你在父页里切换不同文章(子路由变化),如果不加 keepalive,父页的列表状态可能被重置;加上 keepalive: true,切换时父页状态就被稳稳保住。

你还可以把 keepalive 写成对象,传给 <KeepAlive> 更细的参数。比如排除某个组件不被缓存:

<script setup lang="ts">
definePageMeta({
  keepalive: {
    exclude: ['modal'],
  },
})
</script>
Warning

<NuxtPage> 上也可以直接写 keepalive 属性(<NuxtPage keepalive />),效果和页面里的 keepalive: true 类似,但它作用于父路由渲染子页时的缓存策略。两者按需选择,别重复套导致行为难预测。

14-4

除了 titlekeepalivedefinePageMeta 还认识一批有特殊用途的字段。这里先列个速览,后面对应的章节会细讲:

  • layout:指定这个页面用哪个布局(第 16 章)。
  • middleware:进入页面前要跑的中间件(第 19 章)。
  • pageTransition / layoutTransition:页面与布局的过渡动画(第 21 章)。
  • key:控制 <NuxtPage> 何时重新渲染,常用于嵌套路由(第 18 章)。
  • validate:校验当前路由是否合法,不合法可返回 404。
  • alias:给同一个页面起多个可访问的网址别名。
  • redirect:进入这个路由时直接跳转到别处。
<script setup lang="ts">
definePageMeta({
  // 别名:/users/1 和 /u/1 都能访问到这个页面
  alias: ['/u/:id'],
  // 校验:id 必须是数字,否则 404
  validate (route) {
    return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id)
  },
})
</script>

14-5

definePageMeta 在 Nuxt 3 与 Nuxt 4 中写法完全一致,没有目录差异。唯一要留意的是:definePageMeta 的元数据只在「默认路由文件」里读取;如果你用了第 18 章会讲到的「命名视图」(name@view.vue),在命名视图的兄弟文件里写的 meta 不会影响整条路由。

14-6

如果你的页面是嵌套路由(父子页面,见第 18 章),那么父页和子页各自 definePageMeta 里的 meta,会被 Nuxt 合并成一个对象。比如父页设了 titlekeepalive,子页设了 middleware,最终 route.meta 上两者都在。这条合并规则让你能「父页管通用设置、子页管自己的设置」,互不打架。

Note

合并时若父子写了同名字段,子页的值通常覆盖父页。设计多个层级的 meta 时,留意不要无意中互相覆盖。

14-7

你可能会以为,在 definePageMeta 里写了 title: '我的首页',浏览器标签页就会自动显示这个标题。其实不会。definePageMeta 里的 title(以及你写的任何自定义字段)只是被挂到路由的 meta 上,是个「数据」,并不会自动去改 <title> 标签。

这里最容易踩的坑就是:设了 title 却没看到标签页变化,然后以为写法错了。记住——definePageMeta 只负责「存」,不负责「用」。

14-8

要让标签页跟着页面变,得把 route.meta.title 喂给 useHead(或 useSeoMeta)。最常见的是在布局里统一处理一次:

<script setup lang="ts">
const route = useRoute()

// 用函数形式:标题要跟着当前路由动态变化
useHead(() => ({
  title: route.meta.title as string,
}))
</script>

这样每个页面在 definePageMeta 里设的 title,就会变成浏览器标签上的文字。这里特意写成函数 () => ({...}),因为标题得随路由切换实时算,不能写死。如果你只想给某个页面单独设标签名,在该页的 <script setup> 里直接 useHead({ title: '...' }) 也行。

Tip

想顺带把描述、关键词也按页面设置?把 useHead 换成 useSeoMeta,字段名更语义化(如 descriptionogTitle),对搜索引擎更友好。

14-9

前面速览里提到过 aliasredirect,这两个字段常被搞混,区别其实很清楚:

  • alias 是「同一个页面,多个门牌号」:/users/1/u/1 都能进同一页,浏览器地址栏不变,内容一样。
  • redirect 是「进门就被赶去别处」:访问这个路由时,地址会被改写成目标地址,你实际看到的是另一个页面。

一句话记忆:alias 共用一套内容、URL 不改;redirect 换页面、URL 也改。

<script setup lang="ts">
definePageMeta({
  // 旧网址统一引导到新址,地址栏会变成 /blog
  redirect: '/blog',
})
</script>

如果你只是想给一条长网址起个短别名方便分享,选 alias;如果是旧链接废弃要导流,选 redirect

14-10

第 14 章前面说 validate 返回 false 会给 404。其实它还能返回一个对象来「校验失败但跳走」,而不是干巴巴报 404:

<script setup lang="ts">
definePageMeta({
  validate (route) {
    // 不是数字就跳回列表页,比直接 404 更友好
    if (!/^\d+$/.test(route.params.id as string)) {
      return { statusCode: 301, redirect: '/products' }
    }
    return true
  },
})
</script>

validate 返回 { statusCode, redirect } 时,Nuxt 会按你给的状态码做跳转。这比「一律 404」体验更好,也常和路由重定向搭配使用。

14-11

页面元数据就是用 definePageMeta 给页面贴标签。你想存自定义信息就直接写字段、用 route.meta 读;想保住页面状态就开 keepalivetitle 只是数据,要显示到标签页得靠 useHead 接一下。后面几章的布局、中间件、过渡,本质上都是在 definePageMeta 里填对应字段。