2

Currently when using transition in Vue I'm facing the problem that some of the components on the page disappear instantly whereas the rest fade out normally with the whole page.

This is my transition set up as minimal reproducible example, is working here Codepen You can see when switching from Home route to any other route the button disappears instantly while the rest of the view disappears according to the fade properties set using css (and vue transitions).

// https://github.com/groloop/vuejs-2-series
Vue.use(Vuetify);
Vue.use(VueRouter);

var Home = {
  template: '<div> <h2>Home</h2> <v-tooltip left> <template v-slot:activator="{ on }"> <v-btn color="primary" dark v-on="on">Left</v-btn> </template> <span>Left tooltip</span> </v-tooltip> </div>'
}

var AboutUs = {
  template: '<h2>About Us</h2>'
}

var Contact = {
  template: '<h2>Contact</h2>'
}

var NotFound = {
  template: '<h2>Not Found</h2>'
}


var router = new VueRouter({
  history: false,
  routes: [
    { path: '/', name: 'home', component: Home },
    { path: '/about-us', name: 'about-us', component: AboutUs },
    { path: '/contact', name: 'contact', component: Contact },
    { path: '*', name: 'not-found', component: NotFound }
  ],
});

new Vue({
  el: '#app',
  router: router
});
.fade-enter-active,
.fade-leave-active {
  transition-duration: 0.5s;
  transition-property: opacity;
  transition-timing-function: ease-in;
}

.fade-enter-active {
  transition-delay: .5s;
}

.fade-enter,
.fade-leave-active {
  opacity: 0
}
<link href="https://unpkg.com/vuetify@1.5.16/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/vuetify@1.5.16/dist/vuetify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.10/vue.js"></script>
<div id="app">
  <v-toolbar>
    <v-toolbar-title>TEST</v-toolbar-title>
    <v-spacer></v-spacer>
    <v-toolbar-items>
      <v-btn flat href="#/">Home</v-btn>
      <v-btn flat href='#/about-us'>About us</v-btn>
      <v-btn flat href='#/contact'>Contact</v-btn>
      <v-btn flat href='#/test'>Test</v-btn>
    </v-toolbar-items>
  </v-toolbar>
  <transition name="fade" mode="out-in">
    <router-view></router-view>
  </transition>
</div>
Terry
  • 63,248
  • 15
  • 96
  • 118
Alex T
  • 3,529
  • 12
  • 56
  • 105

1 Answers1

2

That's probably due to how v-tooltip works internally. You can see that if you take the button component outside of the template slot in the v-tooltip component, transition works properly.

The v-tooltip component might have a destroy lifecycle hook that simply destroys the rendered DOM node, which can cause issues. A workaround will be to keep the <router-view> alive:

<transition name="fade" mode="out-in">
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>

However, this might not be desirable, especially if you have very heavy components used by the router, or if you have a lot of views to be kept alive:

Solution 1: Cap the max number of components to keep alive

Since you are only concerned with the fading out of the last destroyed component, you can use the max attribute on the <keep-alive> wrapper so that you only keep the last destroyed element. Something like this will work:

<transition name="fade" mode="out-in">
  <keep-alive v-bind:max="2">
    <router-view></router-view>
  </keep-alive>
</transition>

Solution 2: Explicitly include components that need to be kept alive

Alternatively, you can selectively keep the components with <v-tooltip> alive. In your example, only the Home component is having a problem, so you can give it a name:

var Home = {
  template: '<div> <h2>Home</h2> <v-tooltip> <template v-slot:activator="{ on }"> <v-btn color="primary" dark v-on="on">Left</v-btn> </template> <span>Left tooltip</span> </v-tooltip> </div>',
  name: 'Home'
}

And then dynamically bind an array to the include attribute on the <keep-alive> component:

<transition name="fade" mode="out-in">
  <keep-alive :include="componentsToKeepAlive">
    <router-view></router-view>
  </keep-alive>
</transition>

In your JS:

new Vue({
  el: '#app',
  router: router,
  data: {
    componentsToKeepAlive: ['Home']
  }
});
Terry
  • 63,248
  • 15
  • 96
  • 118
  • Thanks, that solves the problem in this case, but I also have similar issue in as you said heavy comopnent. So for instance there is another component that contains chart that also disappears like this button. Do you think "keeping alive" a comopnent like that might be bad for the app performance? – Alex T Apr 01 '20 at 16:17
  • 1
    If you are keeping alive every single component that is rendered, yes, it will be expensive. You can also set the maximum number of components you want to keep alive: after all, you are only concerned with keeping alive the last destroyed component in your router view, so that the fade out works. `` should work fine. – Terry Apr 01 '20 at 21:41