过渡

使用 Vue 或原生浏览器视图转换在页面和布局之间应用转换。
Nuxt 利用 Vue 的 <Transition> 组件在页面和布局之间应用过渡效果。

页面过渡效果

¥Page Transitions

你可以启用页面转换,为所有 pages 应用自动转换。

¥You can enable page transitions to apply an automatic transition for all your pages.

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    pageTransition: { name: 'page', mode: 'out-in' }
  },
})
如果你同时更改布局和页面,则此处设置的页面过渡将不会运行。你应该改为设置 layout transition

要在页面之间添加过渡效果,请将以下 CSS 添加到 app.vue 中:

¥To start adding transition between your pages, add the following CSS to your app.vue:

<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>

在页面之间导航时,此方法会产生以下结果:

¥This produces the following result when navigating between pages:

要为页面设置不同的过渡效果,请在页面的 definePageMeta 中设置 pageTransition 键:

¥To set a different transition for a page, set the pageTransition key in definePageMeta of the page:

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

移动到“关于”页面将添加 3D 旋转效果:

¥Moving to the about page will add the 3d rotation effect:

布局过渡

¥Layout Transitions

你可以启用布局转换,为所有 layouts 应用自动转换。

¥You can enable layout transitions to apply an automatic transition for all your layouts.

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

要在页面和布局之间添加过渡效果,请将以下 CSS 添加到 app.vue 中:

¥To start adding transition between your pages and layouts, add the following CSS to your app.vue:

<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

<style>
.layout-enter-active,
.layout-leave-active {
  transition: all 0.4s;
}
.layout-enter-from,
.layout-leave-to {
  filter: grayscale(1);
}
</style>

在页面之间导航时,此方法会产生以下结果:

¥This produces the following result when navigating between pages:

pageTransition 类似,你可以使用 definePageMeta 将自定义 layoutTransition 应用于页面组件:

¥Similar to pageTransition, you can apply a custom layoutTransition to the page component using definePageMeta:

pages/about.vue
<script setup lang="ts">
definePageMeta({
  layout: 'orange',
  layoutTransition: {
    name: 'slide-in'
  }
})
</script>

全局设置

¥Global Settings

你可以使用 nuxt.config 全局自定义这些默认的过渡名称。

¥You can customize these default transition names globally using nuxt.config.

pageTransitionlayoutTransition 的键都接受 TransitionProps 作为 JSON 可序列化值,你可以在其中传递自定义 CSS 过渡的 namemode 和其他有效的过渡属性。

¥Both pageTransition and layoutTransition keys accept TransitionProps as JSON serializable values where you can pass the name, mode and other valid transition-props of the custom CSS transition.

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    pageTransition: {
      name: 'fade',
      mode: 'out-in' // default
    },
    layoutTransition: {
      name: 'slide',
      mode: 'out-in' // default
    }
  }
})
如果你更改了 name 属性,则还必须相应地重命名 CSS 类。¥If you change the name property, you also have to rename the CSS classes accordingly.

要覆盖全局 transition 属性,请使用 definePageMeta 为单个 Nuxt 页面定义页面或布局过渡,并覆盖在 nuxt.config 文件中全局定义的任何页面或布局过渡。

¥To override the global transition property, use the definePageMeta to define page or layout transitions for a single Nuxt page and override any page or layout transitions that are defined globally in nuxt.config file.

pages/some-page.vue
<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'bounce',
    mode: 'out-in' // default
  }
})
</script>

禁用过渡效果

¥Disable Transitions

可以为特定路由禁用 pageTransitionlayoutTransition

¥pageTransition and layoutTransition can be disabled for a specific route:

pages/some-page.vue
<script setup lang="ts">
definePageMeta({
  pageTransition: false,
  layoutTransition: false
})
</script>

或者,在 nuxt.config 中全局设置:

¥Or globally in the nuxt.config:

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    pageTransition: false,
    layoutTransition: false
  }
})

JavaScript 钩子

¥JavaScript Hooks

对于高级用例,你可以使用 JavaScript 钩子为 Nuxt 页面创建高度动态和自定义的转换效果。

¥For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt pages.

这种方式为 JavaScript 动画库(例如 GSAP)提供了完美的用例。

¥This way presents perfect use-cases for JavaScript animation libraries such as GSAP.

pages/some-page.vue
<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'custom-flip',
    mode: 'out-in',
    onBeforeEnter: (el) => {
      console.log('Before enter...')
    },
    onEnter: (el, done) => {},
    onAfterEnter: (el) => {}
  }
})
</script>
了解更多关于 Transition 组件中可用的其他 JavaScript hooks 的信息。

动态过渡效果

¥Dynamic Transitions

要使用条件逻辑应用动态过渡,你可以利用内联 中间件to.meta.pageTransition 分配不同的过渡名称。

¥To apply dynamic transitions using conditional logic, you can leverage inline middleware to assign a different transition name to to.meta.pageTransition.

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'slide-right',
    mode: 'out-in'
  },
  middleware (to, from) {
    if (to.meta.pageTransition && typeof to.meta.pageTransition !== 'boolean')
      to.meta.pageTransition.name = +to.params.id! > +from.params.id! ? 'slide-left' : 'slide-right'
  }
})
</script>

<template>
  <h1>#{{ $route.params.id }}</h1>
</template>

<style>
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
  transition: all 0.2s;
}
.slide-left-enter-from {
  opacity: 0;
  transform: translate(50px, 0);
}
.slide-left-leave-to {
  opacity: 0;
  transform: translate(-50px, 0);
}
.slide-right-enter-from {
  opacity: 0;
  transform: translate(-50px, 0);
}
.slide-right-leave-to {
  opacity: 0;
  transform: translate(50px, 0);
}
</style>

页面现在在跳转到下一个 ID 时应用 slide-left 过渡,在跳转到上一个 ID 时应用 slide-right 过渡:

¥The page now applies the slide-left transition when going to the next id and slide-right for the previous:

使用 NuxtPage 进行过渡

¥Transition with NuxtPage

<NuxtPage />app.vue 中使用时,可以使用 transition 属性配置过渡效果,以全局激活过渡效果。

¥When <NuxtPage /> is used in app.vue, transitions can be configured with the transition prop to activate transitions globally.

app.vue
<template>
  <div>
    <NuxtLayout>
      <NuxtPage :transition="{
        name: 'bounce',
        mode: 'out-in'
      }" />
    </NuxtLayout>
  </div>
</template>
请记住,此页面转换不能在单个页面上被 definePageMeta 覆盖。

视图转换 API(实验性)

¥View Transitions API (experimental)

Nuxt 附带了 视图转换 API 的实验性实现(参见 MDN)。这是一种令人兴奋的新方法,可以实现原生浏览器过渡效果,它(除其他功能外)能够在不同页面上的不相关元素之间过渡。

¥Nuxt ships with an experimental implementation of the View Transitions API (see MDN). This is an exciting new way to implement native browser transitions which (among other things) have the ability to transition between unrelated elements on different pages.

你可以查看 https://nuxt-view-transitions.surge.shStackBlitz 上的源代码 的演示。

¥You can check a demo on https://nuxt-view-transitions.surge.sh and the source on StackBlitz.

Nuxt 集成正在积极开发中,但可以通过配置文件中的 experimental.viewTransition 选项启用:

¥The Nuxt integration is under active development, but can be enabled with the experimental.viewTransition option in your configuration file:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    viewTransition: true
  }
})

可能的值包括:falsetrue'always'

¥The possible values are: false, true, or 'always'.

如果设置为 true,如果用户浏览器符合 prefers-reduced-motion: reduce(推荐),Nuxt 将不会应用过渡效果。如果设置为 always,Nuxt 将始终应用过渡效果,你可以自行决定是否尊重用户的偏好。

¥If set to true, Nuxt will not apply transitions if the user's browser matches prefers-reduced-motion: reduce (recommended). If set to always, Nuxt will always apply the transition and it is up to you to respect the user's preference.

默认情况下,所有 pages 都启用视图转换,但你可以设置其他全局默认值。

¥By default, view transitions are enabled for all pages, but you can set a different global default.

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    // Disable view transitions globally, and opt-in on a per page basis
    viewTransition: false
  },
})

可以通过在页面的 definePageMeta 中设置 viewTransition 键来覆盖页面的默认 viewTransition 值:

¥It is possible to override the default viewTransition value for a page by setting the viewTransition key in definePageMeta of the page:

pages/about.vue
<script setup lang="ts">
definePageMeta({
  viewTransition: false
})
</script>
只有启用了 experimental.viewTransition 选项,逐页覆盖视图转换才会生效。¥Overriding view transitions on a per-page basis will only have an effect if you have enabled the experimental.viewTransition option.

如果你还使用 Vue 过渡(例如 pageTransitionlayoutTransition,参见上文)来实现与新的 View Transitions API 相同的效果,那么如果用户的浏览器支持较新的原生 Web API,你可能希望禁用 Vue 过渡。你可以通过创建包含以下内容的 ~/middleware/disable-vue-transitions.global.ts 来实现:

¥If you are also using Vue transitions like pageTransition and layoutTransition (see above) to achieve the same result as the new View Transitions API, then you may wish to disable Vue transitions if the user's browser supports the newer, native web API. You can do this by creating ~/middleware/disable-vue-transitions.global.ts with the following contents:

export default defineNuxtRouteMiddleware(to => {
  if (import.meta.server || !document.startViewTransition) { return }

  // Disable built-in Vue transitions
  to.meta.pageTransition = false
  to.meta.layoutTransition = false
})

已知问题

¥Known Issues

  • 如果你在页面设置函数中执行数据提取,则可能需要暂时重新考虑使用此功能。(根据设计,视图转换会在 DOM 更新过程中完全冻结它们。)我们正在考虑将视图转换限制在 <Suspense> 解析之前的最后时刻,但在此期间,如果你有此需求,你可能需要仔细考虑是否采用此功能。