Skip to content
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

Vue-router, transitions and scrollBehavior - Page jumping back to top or changing scroll location #1466

Closed
realcarbonneau opened this issue Jan 22, 2018 · 17 comments

Comments

@realcarbonneau
Copy link
Contributor

There is currently a problem with the vue-router and vue-transitions (outside of Quasar) that causes pages to jump back to the top before transitions and also to change scroll location when doing popstate navigations (browser back and forward buttons. Here are some details, please post comments or questions on this topic here.

vue-router with scrollBehavior currently works when there are NO transitions. The users scroll position will be retained between popstate navigations.

export default new VueRouter({
  // mode: 'history',
  routes,
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      // Keep scroll position when using browser buttons
      return savedPosition
    }
    else {
      return { x: 0, y: 0 }
    }
  }
})

Additionally, to ensure that the component state is retained (eg form field data, opened tabs, etc.) the keep-alive must be used

      <keep-alive>
        <router-view></router-view>
      </keep-alive>

For transitions on routes, there is a new Async scrollBehavior, but there are still some issues that are currently being worked on by the vue team. Here is the current partial solution. Note that the scrollBehavior delay is 1 second and the transition is 0.5s to emphasize the mechanics in play here.

export default new VueRouter({
  // mode: 'history',
  routes,
  scrollBehavior (to, from, savedPosition) {
    let position = { x: 0, y: 0 }
    // Keep scroll position when using browser buttons
    if (savedPosition) {
      position = savedPosition
    }

    // Workaround for transitions scrolling to the top of the page
    // However, there are still some problems being fixed by the vue team
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(position)
      }, 1000)
    })
  }
})

References:
https://router.vuejs.org/en/advanced/scroll-behavior.html

@pdanpdan
Copy link
Collaborator

@realcarbonneau
Copy link
Contributor Author

That is the simplest use case, and it will do jumps in scroll position when combined with transitions.

Note line 24-26 of your example:

  if (savedPosition) {
    // savedPosition is only available for popstate navigations.
    return savedPosition

See the video, it's aweful :S
vueroutertransitionscrollposition

@Jamiewarb
Copy link

I'm also having this issue and looking for a solution

@piotrek-horodenski
Copy link

piotrek-horodenski commented Mar 18, 2018

same problem here, scroll behavior should be invoked not sooner than leave transition finishes, I will probably temporarly fix it with disabling scroll behavior and emulate proper behavior manually

EDIT***
Just found some useful guides how to do it
vuejs/vue-router#1758
https://router.vuejs.org/en/advanced/scroll-behavior.html

@yiqianglin
Copy link

I'm also having this issue and looking for a solution

@tkiley
Copy link

tkiley commented Aug 18, 2018

I had this same problem. It looks like modern browsers set the scroll to savedPosition immediately when you navigate using the browser buttons, so returning a promise from scrollBehavior does not fix the flickering issue entirely.

In order to prevent the browser's default behavior, do this:

if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; }

Perhaps this should be included in the docs or should be set by the router by default?

@pdanpdan
Copy link
Collaborator

Use something along this lines:
In page:

<q-page-container>
  <transition enter-active-class="animated fadeIn" leave-active-class="animated fadeOut" mode="out-in" :duration="200" @after-leave="$root.$emit('triggerScroll')">
    <router-view />
  </transition>
</q-page-container>

In router initialization:

const Router = new VueRouter({
  ...
  scrollBehavior: (to, from, savedPosition) => new Promise((resolve) => {
    const position = savedPosition || {};
    if (!savedPosition) {
      if (to.hash) {
        position.selector = to.hash;
      }
      if (to.matched.some((m) => m.meta.scrollToTop)) {
        position.x = 0;
        position.y = 0;
      }
    }
    Router.app.$root.$once('triggerScroll', () => {
      Router.app.$nextTick(() => resolve(position));
    });
  }),
  routes,
});

@joantune
Copy link

Why is this closed? I'm getting the same issue with the <transition element without using VueRouters

@cybercussion
Copy link

cybercussion commented Apr 12, 2019

Agreed I'm also having this issue still.
I did drop in the aforementioned history.scrollRestoration and after a cache clean reload I think it did solve it.

@nothingismagick
Copy link
Contributor

Did you try this approach example @cybercussion ?
#1466 (comment)

@cybercussion
Copy link

@nothingismagick I used tkiley's approach and its good in Safari/Chrome. I think my cache was sticking.

@Mighty683
Copy link

I had this same problem. It looks like modern browsers set the scroll to savedPosition immediately when you navigate using the browser buttons, so returning a promise from scrollBehavior does not fix the flickering issue entirely.

In order to prevent the browser's default behavior, do this:

if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; }

Perhaps this should be included in the docs or should be set by the router by default?

I think such information should be placed in documentation

@jainsuneet
Copy link

if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; }

This is not working for me. Can you please give me an example ?

This is my code :

export default new VueRouter({
  routes,
  scrollBehavior (to, from, savedPosition) {
    if ('scrollRestoration' in history) { 
        history.scrollRestoration = 'manual'; 
    }
    let position = { x: 0, y: 0 }
    if (savedPosition) {
      position = savedPosition
    }
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(position)
      }, 1000)
    })
  }
}) 

@pdanpdan
Copy link
Collaborator

Please head to VueRouter for this, thank you.

@jainsuneet
Copy link

Please head to VueRouter for this, thank you.

There is no support from Vue, I even tried the documentation Vue Router - Scroll Behaviour but no success.

To every page I navigate back, the page is scrolled to top. Quasar should provide some support on this.

@pdanpdan
Copy link
Collaborator

pdanpdan commented Jan 22, 2020

It's up to you to decide what you need.
Also, as far as I know, vue-router has good docs and even an example here: https://github.com/vuejs/vue-router-demos/blob/master/examples/scroll-behavior/index.js

And Google if full of examples: https://www.google.com/search?q=vue-router+scrollBehaviour+example&pws=0&gl=us&gws_rd=cr

Really, the issues on GitHub are not proxies for people who are too lazy to search:
https://github.com/jeneser/vue-scroll-behavior

@otabekoff
Copy link
Contributor

Good news, if you're experiencing such a problem, just go your favorite code editor(I use VSCode) and search below words over in your project:
scroll-behavior
Then, look each/that file contain's that keyword which is CSS property.
If it has a value called smooth comment or delete that line.
That is making your page to scroll to the top after jumping pages.
But this may cause problems if you're adding Back to top or scrolling components.
Then there is a good solution. Add scroll-behavior: smooth dynamically when just scrolling. After scroll remove it.
You can do it by applying that CSS property to a class. For instance, smooth-scroll.

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