This repository has been archived by the owner on Apr 6, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(getting-started): add
transitions
page (#7987)
Co-authored-by: Sébastien Chopin <seb@nuxtjs.com> Co-authored-by: Clément Ollivier <clement.o2p@gmail.com>
- Loading branch information
1 parent
dc47c64
commit 2310adb
Showing
1 changed file
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,385 @@ | ||
--- | ||
navigation.icon: uil:moon-eclipse | ||
description: Nuxt leverages Vue's Transition component to apply transitions between pages and layouts. | ||
--- | ||
|
||
# Transitions | ||
|
||
Nuxt leverages Vue's [`<Transition>`](https://vuejs.org/guide/built-ins/transition.html#the-transition-component) component to apply transitions between pages and layouts. | ||
|
||
## Page transitions | ||
|
||
Nuxt sets `{ name: 'page', mode: 'out-in' }` transition by default for all your [pages](/guide/directory-structure/pages). | ||
|
||
To start adding transition between your pages, add the following CSS to your [`app.vue`](/guide/directory-structure/app): | ||
|
||
::code-group | ||
|
||
```html [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> | ||
``` | ||
|
||
```html [pages/index.vue] | ||
<template> | ||
<div> | ||
<h1>Home page</h1> | ||
<NuxtLink to="/about">About page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
```html [pages/about.vue] | ||
<template> | ||
<div> | ||
<h1>About page</h1> | ||
<NuxtLink to="/">Home page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
:: | ||
|
||
This produces the following result when navigating between pages: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665061349/nuxt3/nuxt3-page-transitions_umwvmh.mp4" type="video/mp4"> | ||
</video> | ||
|
||
To set a different transition for a page, set the `pageTransition` key in [`definePageMeta`](/api/utils/define-page-meta) of the page: | ||
|
||
::code-group | ||
|
||
```vue [pages/about.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'rotate' | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
```html [app.vue] | ||
<template> | ||
<NuxtPage /> | ||
</template> | ||
|
||
<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> | ||
``` | ||
|
||
:: | ||
|
||
Moving to the about page will add the 3d rotation effect: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665063233/nuxt3/nuxt3-page-transitions-cutom.mp4" type="video/mp4"> | ||
</video> | ||
|
||
## Layouts transitions | ||
|
||
Nuxt sets `{ name: 'layout', mode: 'out-in' }` transition by default for all your [layouts](/guide/directory-structure/layouts). | ||
|
||
To start adding transition between your pages, add the following CSS to your [`app.vue`](/guide/directory-structure/app): | ||
|
||
::code-group | ||
|
||
```html [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> | ||
``` | ||
|
||
```html [layouts/default.vue] | ||
<template> | ||
<div> | ||
<pre>default layout</pre> | ||
<slot /> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
div { | ||
background-color: lightgreen; | ||
} | ||
</style> | ||
``` | ||
|
||
```html [layouts/orange.vue] | ||
<template> | ||
<div> | ||
<pre>orange layout</pre> | ||
<slot /> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
div { | ||
background-color: #eebb90; | ||
padding: 20px; | ||
height: 100vh; | ||
} | ||
</style> | ||
``` | ||
|
||
```html [pages/index.vue] | ||
<template> | ||
<div> | ||
<h1>Home page</h1> | ||
<NuxtLink to="/about">About page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
```html [pages/about.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
layout: 'orange' | ||
}) | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<h1>About page</h1> | ||
<NuxtLink to="/">Home page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
:: | ||
|
||
This produces the following result when navigating between pages: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665065289/nuxt3/nuxt3-layouts-transitions_c9hwlx.mp4" type="video/mp4"> | ||
</video> | ||
|
||
Similar to `pageTransition`, you can apply a custom `layoutTransition` to the page component using `definePageMeta`: | ||
|
||
```vue [pages/about.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
layout: 'orange', | ||
layoutTransition: { | ||
name: 'slide-in' | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
## Global settings | ||
|
||
You can customize these default transition names globally using `nuxt.config`. | ||
|
||
Both `pageTransition` and `layoutTransition` keys accept [`TransitionProps`](https://vuejs.org/api/built-in-components.html#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition. | ||
|
||
```ts [nuxt.config.ts] | ||
export default defineNuxtConfig({ | ||
pageTransition: { | ||
name: 'fade', | ||
mode: 'out-in' // default | ||
}, | ||
layoutTransition: { | ||
name: 'slide', | ||
mode: 'out-in' // default | ||
} | ||
}) | ||
``` | ||
|
||
::alert{type="info"} | ||
If you change the `name` property, you also have to rename the CSS classes accordingly. | ||
:: | ||
|
||
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. | ||
|
||
```vue [pages/some-page.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'bounce', | ||
mode: 'out-in' // default | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
## Disable Transitions | ||
|
||
`pageTransition` and `layoutTransition` can be disabled for a specific route: | ||
|
||
```vue [pages/some-page.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: false | ||
layoutTransition: false | ||
}) | ||
</script> | ||
``` | ||
|
||
Or globally in the `nuxt.config`: | ||
|
||
```ts [nuxt.config.ts] | ||
defineNuxtConfig({ | ||
pageTransition: false, | ||
layoutTransition: false | ||
}) | ||
``` | ||
|
||
## JavaScript Hooks | ||
|
||
For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt pages. | ||
|
||
This way presents perfect use-cases for JavaScript animation libraries such as [GSAP](https://greensock.com/gsap/) or [Tween.js](https://createjs.com/tweenjs). | ||
|
||
```vue [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> | ||
``` | ||
|
||
::alert{type="info"} | ||
Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) available in the `Transition` component. | ||
:: | ||
|
||
## Dynamic Transitions | ||
|
||
To apply dynamic transitions using conditional logic, you can leverage inline [middleware](/guide/directory-structure/middleware) to assign a different transition name to `to.meta.pageTransition`. | ||
|
||
::code-group | ||
|
||
```html [pages/[id].vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'slide-right', | ||
mode: 'out-in' | ||
}, | ||
middleware (to, from) { | ||
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> | ||
``` | ||
|
||
```html [layouts/default.vue] | ||
<script setup lang="ts"> | ||
const route = useRoute() | ||
const id = computed(() => Number(route.params.id || 1)) | ||
const prev = computed(() => '/' + (id.value - 1)) | ||
const next = computed(() => '/' + (id.value + 1)) | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<slot /> | ||
<div v-if="$route.params.id"> | ||
<NuxtLink :to="prev">⬅️</NuxtLink> | | ||
<NuxtLink :to="next">➡️</NuxtLink> | ||
</div> | ||
</div> | ||
</template> | ||
``` | ||
|
||
:: | ||
|
||
The page now applies the `slide-left` transition when going to the next id and `slide-right` for the previous: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665069410/nuxt3/nuxt-dynamic-page-transitions.mp4" type="video/mp4"> | ||
</video> | ||
|
||
## Transition with NuxtPage | ||
|
||
When `<NuxtPage />` is used in `app.vue`, transition-props can be passed directly as a component props to activate global transition. | ||
|
||
```vue [app.vue] | ||
<template> | ||
<div> | ||
<NuxtPage :transition="{ | ||
name: 'bounce', | ||
mode: 'out-in' | ||
}" /> | ||
</NuxtLayout> | ||
</div> | ||
</template> | ||
``` | ||
|
||
::alert{type="warning"} | ||
Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. | ||
:: |