Skip to content

Transition effects when route slug changes #474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jsiebach opened this issue Apr 21, 2016 · 9 comments
Closed

Transition effects when route slug changes #474

jsiebach opened this issue Apr 21, 2016 · 9 comments

Comments

@jsiebach
Copy link

jsiebach commented Apr 21, 2016

Edit: as I finally got this working, I realized it was very similar to vuejs/vuex-router-sync#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.

@hartmut-co-uk
Copy link

Hi @jsiebach
you can use

route: {
    canReuse: false
}

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

@fnlctrl
Copy link
Member

fnlctrl commented Aug 17, 2016

Closing since this is already fixed 😄 .

@fnlctrl fnlctrl closed this as completed Aug 17, 2016
@myst729
Copy link

myst729 commented Oct 17, 2016

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

@posva
Copy link
Member

posva commented Oct 17, 2016

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

@myst729
Copy link

myst729 commented Oct 17, 2016

@posva Yep, this just works for me:

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

@jillztom
Copy link

jillztom commented Oct 26, 2016

Here is a quick tutorial for that I wrote!

@andredewaard
Copy link

@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

@andredewaard
Copy link

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

silverbackdan added a commit to silverbackdan/nuxt.js that referenced this issue Jul 3, 2017
The vue-router component can have a 'key' property which means it's easier to configure transitions between routes with slugs.

With this change in a layout template you can use
```html
<nuxt :routerViewKey="routerViewKey" />
```
And the following for example
```js
    computed: {
      routerViewKey () {
        if (this.$route.name === 'service') {
          return this.$route.name
        } else {
          return this.$route.fullPath
        }
      }
    }
```
This would implement the functionality that @myst729 mentioned here vuejs/vue-router#474 for vue-router - some routes can just switch, but some you may want to transition as though it's a complete new page to an end-user

This is a possible resolution to issue raised here nuxt#1021
@casbloem
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants