Reputation: 2851
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
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
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'
});
Upvotes: 3
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 }
}
}
Upvotes: 0
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'
});
Upvotes: 65
Reputation: 38407
The other answers fail to handle edge cases such as:
http://example.com/foo#bar
should navigate to the element on the page with an id
of bar
.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
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
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