Vue-router: Scroll to top on route change issue on iOS

Created on 9 Oct 2015  ·  18Comments  ·  Source: vuejs/vue-router

I'm building web app with Vue and have some strange behavior on iOS (Safari).
When route changes Safari won't scroll to top of the page (everything's fine on other platforms/browsers)

Has someone faced such problems?

Thanks.

Most helpful comment

The router doesn't automatically scroll to top when the route changes. You can do that in a global before hook though:

router.beforeEach(function (transition) {
  window.scrollTo(0, 0)
  transition.next()
})

All 18 comments

The router doesn't automatically scroll to top when the route changes. You can do that in a global before hook though:

router.beforeEach(function (transition) {
  window.scrollTo(0, 0)
  transition.next()
})

Any elegant way to solve this problem?

Solution @yyx990803 proposed is pretty elegant... Why you don't like it?

Just first impression, I think it's OK now 😀
Thanks for your post.

thanks! @yyx990803, i also have this problem.

Is this available in vue-router@next?

I managed to use this per component

export default{
        data(){
            return {}
        },

        created() {
            //Scrolls to top when view is displayed
            window.scrollTo(0, 0);
        }
    }

But wondering if it is a router configuration

@asantibanez Checkout scrollBehavior https://github.com/vuejs/vue-router/releases

Looks like the arguments for beforeEach are now to, from, next instead of just transition.

https://router.vuejs.org/en/advanced/navigation-guards.html#global-guards

@yyx990803's example would now be:

router.beforeEach(function (to, from, next) {
  window.scrollTo(0, 0)
  next();
})

Setting global scrollBehavior to the router works fine for me, but is there any elegant solution to animate the scrolling of the window within vue-router. I can set my animation in router.beforeEach function, but was just wondering...

@panayotov

Use this

        scrollToTop: function (scrollDuration) {
                var cosParameter = window.scrollY / 2,
                    scrollCount = 0,
                    oldTimestamp = performance.now();

                function step(newTimestamp) {
                    scrollCount += Math.PI / (scrollDuration / (newTimestamp - oldTimestamp));
                    if (scrollCount >= Math.PI) window.scrollTo(0, 0);
                    if (window.scrollY === 0) return;
                    window.scrollTo(0, Math.round(cosParameter + cosParameter * Math.cos(scrollCount)));
                    oldTimestamp = newTimestamp;
                    window.requestAnimationFrame(step);
                }

                window.requestAnimationFrame(step);
            }

https://stackoverflow.com/questions/21474678/scrolltop-animation-without-jquery

The fix would scroll current page to top then do the route. That's not what people want if they have route animation.

@pajtai - Stupid question here. Where do I add that customization? I have a webpack application with my main.js as :

```import Vue from 'vue'
import Vuetify from 'vuetify'
import App from './App'
import router from './router'

Vue.use(Vuetify)
Vue.config.productionTip = false

new Vue({
el: '#app',
router,
render: h => h(App)
})
`` I tried inserting into my main.js before thenew Vue` bit, but it didn't work.

Just wanted to piggyback @jesong's comment and (re?)highlight this problem. Using beforeEach to scroll causes the page to scroll before any route animation is made, which doesn't look too good.

For those that want to apply the animation after the route has changed, or doesn't want that odd flicker of the view when using the scrollTop in a beforeEach. You are always welcome to use the afterEach hook provided by the router.

router.afterEach(() => {
  window.scrollTo(0, 0);
});

Reference: https://router.vuejs.org/en/api/router-instance.html

This is better (scrollBehavior):

export default new Router({
  scrollBehavior() {
    return { x: 0, y: 0 };
  },
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }
  ],
  mode: 'history'
});

See https://router.vuejs.org/guide/advanced/scroll-behavior.html#async-scrolling

@yyx990803 thanks it worked for me.

@edarioq
I had an ugly jump to the top of the current page before leaving.
I put the window.scrollTo(x, y) in the beforeCreate() hook and it worked

This is better (scrollBehavior):

export default new Router({
  scrollBehavior() {
    return { x: 0, y: 0 };
  },
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }
  ],
  mode: 'history'
});

See https://router.vuejs.org/guide/advanced/scroll-behavior.html#async-scrolling

Thank you for the solution. This is working for my project.

Was this page helpful?
0 / 5 - 0 ratings