]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
docs: transitions
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 31 Aug 2020 16:58:02 +0000 (18:58 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Tue, 1 Sep 2020 07:49:35 +0000 (09:49 +0200)
docs/guide/advanced/transitions.md
playground/App.vue
playground/index.html
playground/router.ts
playground/views/RepeatedParams.vue [new file with mode: 0644]

index 9d525525988525e29d716154b1b633ab12e8f400..0cde4b79bca3ea37e28d7a8538c0faf0dd430db7 100644 (file)
@@ -1,60 +1,59 @@
 # Transitions
 
-Since the `<router-view>` is essentially a dynamic component, we can apply transition effects to it the same way using the `<transition>` component:
+In order to use transitions on your route components and animate navigations, you need to use the [v-slot API](../../api#v-slot):
 
 ```html
-  <router-view v-slot="{ Component }">
-    <transition>
-      <component :is="Component" />
-    </transition>
-  </router-view>
+<router-view v-slot="{ Component }">
+  <transition name="fade">
+    <component :is="Component" />
+  </transition>
+</router-view>
 ```
 
 [All transition APIs](https://vuejs.org/guide/transitions.html) work the same here.
 
 ## Per-Route Transition
 
-The above usage will apply the same transition for all routes. If you want each route's component to have different transitions, you can instead use `<transition>` with different names inside each route component:
+The above usage will apply the same transition for all routes. If you want each route's component to have different transitions, you can instead combine [meta fields](./meta.md) and a dynamic `name` on `<transition>`:
 
 ```js
-const Foo = {
-  template: `
-    <transition name="slide">
-      <div class="foo">...</div>
-    </transition>
-  `
-}
-
-const Bar = {
-  template: `
-    <transition name="fade">
-      <div class="bar">...</div>
-    </transition>
-  `
-}
+const routes = [
+  { path: '/custom-transition', meta: { transition: 'slide-left' } },
+  { path: '/other-transition', meta: { transition: 'slide-right' } },
+]
+```
+
+```html
+<router-view v-slot="{ Component, route }">
+  <!-- Use any custom transition and fallback to `fade` -->
+  <transition :name="route.meta.transition || 'fade'">
+    <component :is="Component" />
+  </transition>
+</router-view>
 ```
 
 ## Route-Based Dynamic Transition
 
-It is also possible to determine the transition to use dynamically based on the relationship between the target route and current route:
+It is also possible to determine the transition to use dynamically based on the relationship between the target route and current route. Using a very similar snippet to the one just before:
 
 ```html
 <!-- use a dynamic transition name -->
-<transition :name="transitionName">
-  <router-view></router-view>
-</transition>
+<router-view v-slot="{ Component, route }">
+  <transition :name="route.meta.transition">
+    <component :is="Component" />
+  </transition>
+</router-view>
 ```
 
+We can add an [after navigation hook](./navigation-guards.md#global-after-hooks) to dynamically add information to the `meta` field based on the depth of the route
+
 ```js
-// then, in the parent component,
-// watch the `$route` to determine the transition to use
-watch: {
-  '$route' (to, from) {
-    const toDepth = to.path.split('/').length
-    const fromDepth = from.path.split('/').length
-    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
-  }
-}
+router.afterEach((to, from) => {
+  const toDepth = to.path.split('/').length
+  const fromDepth = from.path.split('/').length
+  to.meta.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
+})
 ```
 
-See full example [here](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).
+<!-- TODO: interactive example -->
+<!-- See full example [here](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js). -->
index 62aec5f34d2e27a4a5d719e045723a4c23e4b006..20e7de8bb8afd5009a838e8718457531a12be65f 100644 (file)
     <button @click="toggleViewName">Toggle view</button>
     <Suspense>
       <template #default>
-        <router-view :name="viewName" v-slot="{ Component }">
+        <router-view :name="viewName" v-slot="{ Component, route }">
           <transition
-            name="fade"
+            :name="route.meta.transition || 'fade'"
             mode="out-in"
             @before-enter="flushWaiter"
             @before-leave="setupWaiter"
           >
             <keep-alive>
-              <component :is="Component" />
+              <component
+                :is="Component"
+                :key="route.name === 'repeat' ? route.path : undefined"
+              />
             </keep-alive>
           </transition>
         </router-view>
       </template>
-      <template #fallback>
-        Loading...
-      </template>
+      <template #fallback> Loading... </template>
     </Suspense>
   </div>
 </template>
index f2874ec9a3f7fe09bec15e2bde23108cbe4be0f3..396abe5d461f44afa136aba3874b045fa38908d2 100644 (file)
@@ -20,7 +20,7 @@
       }
       .fade-enter-active,
       .fade-leave-active {
-        transition: opacity 0.15s ease;
+        transition: opacity 0.3s ease;
       }
       .fade-enter-from,
       .fade-leave-to {
         position: absolute;
         transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1);
       }
+      .slide-left-enter-active,
+      .slide-left-leave-active,
+      .slide-right-enter-active,
+      .slide-right-leave-active {
+        transition: all 0.3s;
+      }
       .slide-left-enter-from,
       .slide-right-leave-to {
         opacity: 0;
index 924dccb19bc8580664a98aed10126ac06f3978b1..6e6e713844fc6185e3b7dbab4b16dbff1adcd7b0 100644 (file)
@@ -14,6 +14,7 @@ import GuardedWithLeave from './views/GuardedWithLeave.vue'
 import ComponentWithData from './views/ComponentWithData.vue'
 import { globalState } from './store'
 import { scrollWaiter } from './scrollWaiter'
+import RepeatedParams from './views/RepeatedParams.vue'
 let removeRoute: (() => void) | undefined
 
 export const routerHistory = createWebHistory()
@@ -42,6 +43,7 @@ export const router = createRouter({
     { path: '/long-:n', name: 'long', component: LongView },
     {
       path: '/lazy',
+      meta: { transition: 'slide-left' },
       component: async () => {
         await delay(500)
         return component()
@@ -77,7 +79,7 @@ export const router = createRouter({
       ],
     },
     { path: '/with-data', component: ComponentWithData, name: 'WithData' },
-    { path: '/rep/:a*', component: component, name: 'repeat' },
+    { path: '/rep/:a*', component: RepeatedParams, name: 'repeat' },
     { path: '/:data(.*)', component: NotFound, name: 'NotFound' },
     {
       path: '/nested',
@@ -189,6 +191,14 @@ router.beforeEach((to, from, next) => {
   next()
 })
 
+router.afterEach((to, from) => {
+  if (to.name === from.name && to.name === 'repeat') {
+    const toDepth = to.path.split('/').length
+    const fromDepth = from.path.split('/').length
+    to.meta.transition = toDepth < fromDepth ? 'slide-right' : 'slide-left'
+  }
+})
+
 router.afterEach((to, from) => {
   // console.log(
   //   `After guard: from ${from.fullPath} to ${
diff --git a/playground/views/RepeatedParams.vue b/playground/views/RepeatedParams.vue
new file mode 100644 (file)
index 0000000..cafdb2d
--- /dev/null
@@ -0,0 +1,39 @@
+<template>
+  <div>
+    <div>Repeated Params</div>
+    <router-link :to="lessNesting">Less nesting</router-link>
+    <br />
+    <router-link :to="moreNesting">More nesting</router-link>
+    <pre>{{ moreNesting }}</pre>
+    <pre>{{ lessNesting }}</pre>
+  </div>
+</template>
+
+<script>
+import { defineComponent, computed } from 'vue'
+import { useRoute } from '../../src'
+
+export default defineComponent({
+  name: 'RepeatedParams',
+
+  setup() {
+    const route = useRoute()
+
+    const lessNesting = computed(() => {
+      const a = [...(route.params.a || [])]
+      a.pop()
+
+      return { params: { a } }
+    })
+
+    const moreNesting = computed(() => {
+      const a = [...(route.params.a || [])]
+      a.push('more')
+
+      return { params: { a } }
+    })
+
+    return { lessNesting, moreNesting }
+  },
+})
+</script>