Search code examples
frontendvuejs3nuxt3.js

Change animation based on previous page in Vue3/Nuxt3


I am currently working on adding transitions to the home page of a Nuxt3/Vue3 application. I am using the <Transition> tag for it:

<template>
  <Transition name="slide-left" mode="out-in">
    ...
  </Transition>
</template>

I want to use a different transition based on the page I am coming from, for example if I am coming from 'gallery' the transition name should be 'slide-left', but if I am coming from 'intro' it should be 'dissolve' instead. How can I achieve that?


Solution

  • I found a way to do this, though admittedly it seems more complicated than it should be. I also don't use Nuxt, though that problably shouldn't affect the answer either way, less import statements if anything. Anyways, the main obstacle is figuring out what the previous route was, since neither useRoute or useRouter contains this information. We have to use one of Vue Router's navigation guards which feature the from parameter containing the information we need, namely the beforeRouteEnter guard.

    The other problem then is getting this information to the component, since this navigation guard executes before the component is created, my best idea is to use a very simple composable (or store would work), that the Vue Router guard can write to and the component can read from. (side note: I tried a way using the next param of BeforeRouteEnter to set a local variable on vm, and while I could set a variable, I was unable to affect the transition animation when doing so. Probably a timing issue with the guard and component mounting)

    The composable: prevRoute.js

    import { ref } from "vue";
    
    const prevRoute = ref();
    
    export default prevRoute;
    

    Component <script> (BeforeRouteEnter is only available with Options API)

    <script>
    export default {
      beforeRouteEnter(_, from) {
        prevRoute.value = from
      }
    }
    </script>
    

    Followed by regular <script setup> Composition API for the rest

    <script setup>
    import { ref } from 'vue'
    import prevRoute from '../composables/prevRoute'
    
    const transition = ref('')
    if (prevRoute.value) {
      if (prevRoute.value.name === 'someRouteName') {
        transition.value = 'bounce'
      } else {
        transition.value = 'slide-fade'
      }
    }
    </script>
    

    example codesandbox -- navigate to Page1 or Page2 then navigate back to see the from-based transition.