It seems like the router setup for the JSS Vue example may be preventing the transitions that are built into Vue Router from properly running. Specifically I am having issues with the leave animation. It seems like it either gets skips or the enter state runs too quickly. The enter animation works fine and I have also used this before on more simple Vue app builds.

This is the code I added to AppRoot.vue

<template>
  <div class="app-root">
    <context-view :visible="contextViewVisible" />
    <!-- 'router-view' is a "global" component that is injected into the Vue component registry by vue-router. -->
    <transition name="slide-fade">
      <router-view v-if="!languageIsChanging" />
    </transition>

    <div v-if="languageIsChanging" class="alert alert-info">Language is changing...</div>
  </div>
</template>

As well as the CSS for the transition animations:

  .slide-fade-enter-active {
    transition: all 0.5s ease;
    transition-delay: 2s;
  }
  .slide-fade-leave-active {
    transition: all 1s cubic-bezier(1, 0.5, 0.8, 1);
  }
  .slide-fade-enter, .slide-fade-leave-to
  /* .slide-fade-leave-active below version 2.1.8 */ {
    transform: translateX(30px);
    opacity: 0;
  }

My guess is that it has something to do with how the dynamic routes are being fetched and the logic in RouteHandler.vue. I'm wondering if there are any other more simple examples of route handling that only deal with fetching the right components and mounting them with the data from SiteCore (no language switcher and graphQL stuff).

Any help is appreciated!

up vote 0 down vote accepted

I think the issue you're encountering is due to the loading state transitions within the RouteHandler component that is rendered by the <router-view />. In the code you've provided, the <transition> gets applied to whatever is rendered by the <router-view /> component (which is ultimately the RouteHandler component in the sample apps).

However, because route data retrieval is asynchronous, the RouteHandler will enter the loading state and render a <route-loading /> component while route data is being retrieved. After route data has been retrieved, the RouteHandler will render the <layout /> component. The <router-view /> component is therefore technically "swapping" separate components and the <transition> that wraps <router-view /> is trying to apply the transition to each component that <router-view /> renders.

All of that said, it seems like the most straightforward solution might be to move the <transition /> into the RouteHandler component, directly wrapping the components declared in its template. Then also use the transition mode property on the <transition /> component, which is explained in the Vue docs: https://vuejs.org/v2/guide/transitions.html#Transition-Modes

For example:

<transition name="slide-fade" mode="out-in">
  <not-found v-if="notFound" :context="appState.sitecoreContext" />
  <route-loading v-else-if="loading"  />
  <layout v-else :route="appState.routeData" />
</transition>

I also adjusted the css a bit, just to remove the transition-delay:

.slide-fade-enter-active {
  transition: all 0.5s ease;
}
.slide-fade-leave-active {
  transition: all 1s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter, .slide-fade-leave-to
  /* .slide-fade-leave-active below version 2.1.8 */ {
  transform: translateX(30px);
  opacity: 0;
}

The transition should then behave like:

Current element transitions out first, then when complete, the new element transitions in.

You may need to experiment with transition timings and delays to achieve your desired effect, but I believe this is the path you'll need to explore.

Alternatively, you may wish to replace the <route-loading /> component in the sample app with your own transition / loading indicator.

  • Yep, exactly the conclusion I have come to. I tried the mode option but no luck with that either. The best solution I have is adding custom events that fire my animations and then call this.$router.push(newRoute) after a setTimeout delay for how long the animation lasts. This does pretty well, but I get a screen flash, like the <route-loading> component briefly loads and before the <layout> component gets it's data and is shown again. I wonder if there is anyway to prevent the route change until the async data comes back and the <layout> just gets data updated and no unmount – atflick Sep 19 at 18:42
  • I was able to get it working (I think) by moving the <transition /> into RouteHandler. I'll update the answer. – Adam Weber Sep 19 at 19:01
  • AHHH I think this works!! I swear I tried this but maybe not with the mode... Thank you so much! – atflick Sep 19 at 19:28
  • Cool! Yeah, I just tried it on a clean Vue sample app (via jss create) and the code above seemed to trigger a distinct fade leave and fade enter transition when clicking on routes in the nav. – Adam Weber Sep 19 at 19:30

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.