Vue-router: Transition effects when route slug changes

Created on 22 Apr 2016  路  9Comments  路  Source: vuejs/vue-router

Edit: as I finally got this working, I realized it was very similar to https://github.com/vuejs/vuex-router-sync/issues/3 . The ability to call actions within router hooks ended up being what solved it. So I guess this may be fixed when router hooks are simplified. But the ability to put a transition on a watched variable still makes sense, so I'm posting this anyway.


TL;DR: It would be a feature to allow a transition when data changes. IE if you have <span>Name: {{name}}</span> and name is changed, it would fade-out and then fade-in.


I've used <router-view transition="fade" transition-mode="in-out"> to provide a fade-out, fade-in effect when changing from one route to another. Now I'm having trouble doing the same thing where the route slug changes, but the component and the route are remaining the same.

I've got a Page component that uses a vuex getter to return the content of the current page based on the URL. The route is available in the state thanks to vuex-router-sync:

function getCurrentPage (state) {
  var pages = state.pages.filter(page => page.slug === state.route.params.slug)
  return pages.length ? pages[0] : {}
}

Then I am able to access the current page via this getter in my Page.vue component:

<template>
  <div>
    <div class="content-header">
      <h1>{{{page.title.rendered}}}</h1>
    </div>
    <div class="content-body">
      {{{page.content.rendered}}}
    </div>
  </div>
</template>
<script type="text/babel">
  import {getCurrentPage} from './../vuex/getters'
  export default {
    name: 'Page',
    vuex: {
      getters: {
        page: getCurrentPage
      }
    }
  }
</script>

So when the URL updates, the page content immediately updates. I cannot seem to find a way to use a fade-out, fade-in effect on this change.

1) Since the route is not changing, the <router-view> transition is not triggered
2) Since the component is not changing, I can't use an :is="component" transition

I tried a couple of things, like placing a setTimeout in the route.data() function that delayed next() by some time:

    route: {
      data ({next}) {
        setTimeout(()=>{
          next()
        },150);
      }
    }

Then I hid the component during $routeDataLoading. I got a proper fade out fade in effect, however the page variable updated immediately, so the page content updated before the fade-out even began.

What I finally did to get it going was a hack to allow actions within router hooks:

route: {
      data ({to,next}) {
        setTimeout(()=>{
          next({
            page:getCurrentPage(to.router.app.$store.state)
          })
        },150);
      }
    }

Since my fade is .15s, this faded out the div during $routeDataLoading, and then faded it back perfectly .15s later when the timeout finished.

Most helpful comment

@posva Yep, this just works for me:

<transition name="view" mode="out-in" appear>
  <router-view :key="$route.fullPath"></router-view>
</transition>

All 9 comments

Hi @jsiebach
you can use

route: {
    canReuse: false
}

to get a fresh component invoking all transition hooks and effects..!

Closing since this is already fixed :smile: .

The solution no longer works with vue-router 2.x, canReuse: false deprecated. Any ideas?

@myst729 Using the key attribute with a computed property should work

@posva Yep, this just works for me:

<transition name="view" mode="out-in" appear>
  <router-view :key="$route.fullPath"></router-view>
</transition>

Here is a quick tutorial for that I wrote!

@myst729 Is it also possible to do this for only a specific route? I have a transition on all my pages like: /blog, /about-us etc. I want the transition to also happen on /blog/:slug but not on /service/:slug

Nevermind i fixed it with a computed route like this:
computed: { key () { if(this.$route.name == 'service') { return this.$route.name } else { return this.$route.fullPath } } }
Then the key stays the same on the service page. But changes anywhere else

@andre-dw maybe just using an if in key prop is better. Computed seems overload

Was this page helpful?
0 / 5 - 0 ratings