首页 / Nuxt 4 入门教程 / 路由过渡动画

Nuxt 4 入门教程

路由过渡动画

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

NuxtNuxt4过渡动画TransitionpageTransition

本节目标:理解 Nuxt 的页面过渡机制,能给页面切换加上淡入淡出等动画,并知道单根元素的硬性要求。

21-1

页面切换时那种「旧页淡出、新页淡入」的效果,Nuxt 是借用了 Vue 自带的 <Transition> 组件实现的。Nuxt 在 <NuxtPage> 外层自动包了一层 <Transition>,并通过 transitionname 去匹配你写的 CSS 类,从而产生动画。

也就是说,你不用自己写 <Transition> 标签,只要告诉 Nuxt「这个过渡叫什么名字」,再补上对应的 CSS,动画就出来了。

Warning

被动画的页面或布局必须有单一根元素。如果一个 .vue 模板里有多个并列的根节点(或用 HTML 注释当占位),Vue 的 <Transition> 无法判断动画套在哪个节点上,过渡就不会跑,开发模式下 Nuxt 还会给出警告。最稳妥的做法是用一个 <div> 把内容包起来。注意:HTML 注释在模板里也算一个「元素」,别留着。

21-2

先在 nuxt.config 里给所有页面设一个默认过渡名(这里叫 page),并指定模式 out-in(先让旧页完全离开,再让新页进入):

export default defineNuxtConfig({
  app: {
    pageTransition: { name: 'page', mode: 'out-in' },
  },
})

然后在 app.vue 里写上对应的 CSS。Vue 的过渡约定:进入时加 .page-enter-from / .page-enter-active / .page-enter-to,离开时加 .page-leave-from / .page-leave-active / .page-leave-to。我们一般只写 from(起始态)和 active(过渡过程),让 to 回到默认样式。

<template>
  <NuxtPage />
</template>

<style>
.page-enter-active,
.page-leave-active {
  transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
  opacity: 0;
  filter: blur(1rem);
}
</style>

这样,所有页面切换都会带上「0.4 秒淡出 + 模糊」的效果。

Note

如果你在切换时同时换了布局又换了页面,Nuxt 会优先播放「布局过渡」而不是这里设的「页面过渡」。那种情况请改用第 16 章布局 + 下面的 layoutTransition 配置。

21-3

想让某一页用不同的动画?在那页的 definePageMeta 里覆盖 pageTransitionname 即可,其它页不受影响。

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'rotate',
  },
})
</script>

对应的 CSS 用 rotate- 前缀:

<style>
.rotate-enter-active,
.rotate-leave-active {
  transition: all 0.4s;
}
.rotate-enter-from,
.rotate-leave-to {
  opacity: 0;
  transform: rotate3d(1, 1, 1, 15deg);
}
</style>
Tip

改了 name,CSS 类名也要跟着改,否则动画不生效。这是最容易忘的一点:名字和类名必须一一对应。

21-4

布局也能有过渡,配置项和页面几乎一样,只是前缀变成 layout

export default defineNuxtConfig({
  app: {
    layoutTransition: { name: 'layout', mode: 'out-in' },
  },
})

CSS 对应 .layout-enter-active 等类。某个页面不想用过渡,把值设 false

<script setup lang="ts">
definePageMeta({
  pageTransition: false,
  layoutTransition: false,
})
</script>

全局关闭也行,在 nuxt.config 里把两项都设 false 即可。

21-5

想要更花哨的动画(比如用 GSAP 这类 JS 动画库),可以用 onBeforeEnter / onEnter / onAfterEnter 等 JS 钩子:

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'custom-flip',
    mode: 'out-in',
    onBeforeEnter: (el) => {
      console.log('进入之前...', el)
    },
  },
})
</script>

还能根据路由动态切换动画方向:在 definePageMeta 里写一个 middleware 函数,根据 to / from 的参数大小,把 to.meta.pageTransition.name 改成 slide-leftslide-right,做出「前进左滑、后退右滑」的体验。

21-6

从 Nuxt 4.4 起,还实验性地支持浏览器原生的 View Transitions API(能跨页面对不相关元素做过渡)。在 nuxt.config 开启:

export default defineNuxtConfig({
  experimental: {
    viewTransition: true,
  },
})

取值可为 falsetrue'always'true 会在用户系统开启「减少动态效果」时自动禁用(推荐),'always' 则强制开启。自 Nuxt 4.4 起还支持 view transition types,能为「前进/后退」配置不同 CSS 动画;这些类型可在 definePageMetaviewTransition 里按页设置。

Warning

View Transitions API 仍是实验特性,且需浏览器支持。它和 Vue 的 pageTransition 是两套机制:用了原生 API,可以考虑用全局中间件把 Vue 过渡关掉,避免两者打架。生产环境使用前请确认目标用户浏览器兼容性。

21-7

pageTransition / layoutTransitiondefinePageMeta 配置方式在 Nuxt 3、Nuxt 4 一致。View Transitions API 是 Nuxt 4.4+ 的实验特性,Nuxt 3 不支持;本教程基线 Nuxt 4.5.2 已可用,但仍建议谨慎用于生产。

21-8

前面例子里 mode: 'out-in' 表示「先出后进」。Vue 的过渡默认是「新旧同时过渡」(进出重叠)。页面切换时,两个页面同时占屏容易布局抖动,所以 Nuxt 官方示例都用 out-in,等旧页完全离开再让新页进入,视觉更稳。

21-9

若动画没出现,按顺序检查这几点:页面是否有单一根元素(最常见坑);name 和 CSS 类名前缀是否一致;pageTransition 是否在某处被设成了 false<NuxtPage> 是否真的在 app.vue 里。开发模式下 Nuxt 对「多根元素」会直接警告,看到警告先解决它。

Tip

过渡和 key 配合很好用:给 <NuxtPage> 设不同 key,能强制在觉得「需要重播动画」的时机重新触发过渡,做出列表项切换、卡片翻面等效果。

21-10

Nuxt 的过渡靠 Vue 的 <Transition> 实现,而 <Transition> 的动画完全由 CSS 类驱动。规则是:你给过渡起一个 name(比如 page),Vue 就会在动画不同阶段自动给元素加上 name-enter-fromname-enter-activename-enter-toname-leave-fromname-leave-activename-leave-to 这六个类。你通常只需写 from(起始状态)和 active(过渡时长与曲线),to 回到元素默认样式即可省略。

对应关系就一句话:CSS 类名的 前缀 = 你在 pageTransition 里设的 name。所以:

  • name: 'page' → 写 .page-enter-from 等;
  • name: 'rotate' → 写 .rotate-enter-from 等;
  • name: 'slide-left' → 写 .slide-left-enter-from 等。

名字写错,或 CSS 前缀对不上,动画就完全不触发——这是新手排错第一要看的地方。回到第 21 章开头的全局例子:我们在 nuxt.configname: 'page'app.vue 里写的正是 .page-enter-from,前后对上了,动画才生效。

Tip

如果你改了 name 却忘了改 CSS 前缀,开发模式下 Nuxt 不会报错,只是「切页毫无动画」。遇到这种情况,先核对一遍 name 和类名前缀是否一字不差。

21-11

pageTransition(页面级)作用在 <NuxtPage> 渲染的那块区域:切换页面时,旧页淡出、新页淡入。

layoutTransition(布局级)作用在 <NuxtLayout> 包裹的那一层:切换布局时(比如从前台 default 跳到后台 admin),旧外壳淡出、新外壳淡入。

两者的核心区别是作用范围:页面级只动「内容区」,外壳不动;布局级动的是「整个外壳」。如果你同时换了布局又换了页面,Nuxt 优先播布局级过渡——因为外层先变、内层再变更符合直觉。

Note

不是每次切换都有布局过渡。只有「布局名变了」才会触发 layoutTransition;同一布局内换页面,播的是 pageTransition。别把两者搞混,否则会疑惑「我明明设了 layoutTransition 怎么没反应」——很可能你只是换了页面、没换布局。

21-12

除了淡入淡出,这几个配方最常用,机制完全一致:设好 name,再写对应的 from / leave-to 即可。

  • 左滑进场:.slide-left-enter-from { transform: translateX(100%) }.slide-left-leave-to { transform: translateX(-100%) }
  • 上浮进场:.fade-up-enter-from { opacity: 0; transform: translateY(20px) }
  • 缩放进场:.zoom-enter-from { opacity: 0; transform: scale(0.95) }

配合前面讲过的「用中间件动态切换 pageTransition.name」,你就能做出「前进左滑、后退右滑」的体验:监听 tofrom 在路由树里的深度,深了用 slide-left,浅了用 slide-right

Warning

这些配方都依赖「页面有单一根元素」。如果页面模板里根节点不止一个,Vue 不知道把 transform 套到哪个节点上,动画依然会失效。写动画前先确认根元素唯一,这一条比选哪个配方都重要。

21-13

页面过渡靠 Vue 的 <Transition> + name 对应的 CSS 类实现;name 是什么,CSS 类名前缀就得是什么。全局在 nuxt.configpageTransition/layoutTransition,单页用 definePageMeta 覆盖;页面级动内容区、布局级动外壳。记牢「页面必须有单一根元素」这条铁律。到本章为止,视图与路由这一大块的九个知识点就讲完了。