frosty
frosty

Reputation: 2851

Vue.js scroll to top of new page route after setTimeout

I have a page transition that doesn't work nicely when the scroll to the top of a new route is instant. I'd like to wait 100ms before it automatically scrolls to the top. The following code doesn't end up scrolling at all. Is there a way to do this?

export default new Router({
    mode: 'history',
    routes: [
        {
            path: '/',
            name: 'Home',
            component: Home
        }
    ],
    scrollBehavior (to, from, savedPosition) {
        setTimeout(() => {
            return { x: 0, y: 0 }
        }, 100);
    }
})

Upvotes: 28

Views: 37572

Answers (7)

shasi kanth
shasi kanth

Reputation: 7094

It is as simple as this code:

const router = createRouter({
    history: createWebHistory(),
    scrollBehavior(to, from, savedPosition) {
        return { top: 0 } // always scroll to top
    },
    routes,
});

Upvotes: 0

Edwin Donaldo
Edwin Donaldo

Reputation: 31

If you want to wait a long time use Async Scrolling of scrollBehaviour, like this:

export default new Router({
  scrollBehavior() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({ x: 0, y: 0 })
      }, 100)
    })
  },
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }
  ],
  mode: 'history'
});

More here.

Upvotes: 3

siva hari
siva hari

Reputation: 131

When using client-side routing, we may want to scroll to top when navigating to a new route, or preserve the scrolling position of history entries just like real page reload does. vue-router allows you to achieve these and even better, allows you to completely customize the scroll behavior on route navigation.

Note: this feature only works if the browser supports history.pushState.

scrollBehavior (to, from, savedPosition) {
  return { x: 0, y: 0 }
}

With Saved Position:

scrollBehavior (to, from, savedPosition) {
  if (savedPosition) {
    return savedPosition
  } else {
    return { x: 0, y: 0 }
  }
}

For more information

Upvotes: 0

Edgar Quintero
Edgar Quintero

Reputation: 4441

This is natively supported by Vue now, use scrollBehaviour, like this:

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

More here.

Upvotes: 65

Muhammad Rehan Saeed
Muhammad Rehan Saeed

Reputation: 38407

The other answers fail to handle edge cases such as:

  1. Saved Position - The saved position occurs when the user clicks the back or forward positions. We want to maintain the location the user was looking at.
  2. Hash Links - E.g. http://example.com/foo#bar should navigate to the element on the page with an id of bar.
  3. Finally, in all other cases we can navigate to the top of the page.

Here is the sample code that handles all of the above:

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
  scrollBehavior: (to, from, savedPosition) => {
    if (savedPosition) {
      return savedPosition;
    } else if (to.hash) {
      return {
        selector: to.hash
      };
    } else {
      return { x: 0, y: 0 };
    }
  }
});

Upvotes: 25

PatDuJour
PatDuJour

Reputation: 975

If you want this to happen on every route, you can do so in the before hook in the router:

const router = new VueRouter({ ... })

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

If you are on an older version of vue-router, use:

router.beforeEach(function (transition) { 
    setTimeout(() => {
        window.scrollTo(0, 0);
    }, 100);
    transition.next();
});

Upvotes: 12

frosty
frosty

Reputation: 2851

This is probably not the best way, but adding

document.body.scrollTop = document.documentElement.scrollTop = 0;

in a route's core component's (in this case, Home) mounted() function achieves what I want.

Upvotes: 1

Related Questions