How can I prevent the page from scrolling to the top when I change the route's query param (and the view's props
)?
I've tried the following with no luck:
Attempt 1 - Route's component
When I make the timeout an arbitrarily large number (1 second) then it scrolls back down after some delay.
// in my route's component
props: {...},
watch: {
$route(to, from) {
let y = window.scrollY;
this.$nextTick(() => {
setTimeout(() => {
console.log(`scrolling to ${y}`);
window.scrollTo(0, y);
}, 0);
});
}
}
Attempt 2 - $router's scrollBehavior
This logs the correct y
value, but doesn't maintain the old position.
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
if (from.path !== to.path) {
return { x: 0, y: 0 };
}
let existing = {
x: window.scrollX,
y: window.scrollY
};
console.log(`Existing scroll`, existing);
return new Promise(resolve => {
setTimeout(() => {
resolve(existing);
}, 0);
});
},
Remarks to other answers:
1. hashbag: true,
. Neither hashbag
nor hashbang
I can find in the current version of vue-router docs. Probably this is an old attribute.
2. if (to.params.savePosition) return {}
+ this.$router.push({ query: query, params: { savePosition: true } })
No need to use additional param, as savePosition
as a fix of this issue.
My answer with comments:
const router = new VueRouter({
mode: 'history', // or 'hash'
routes,
scrollBehavior (to, from, savedPosition) {
// Exists when Browser's back/forward pressed
if (savedPosition) {
return savedPosition
// For anchors
} else if (to.hash) {
return { selector: to.hash }
// By changing queries we are still in the same component, so "from.path" === "to.path" (new query changes just "to.fullPath", but not "to.path").
} else if (from.path === to.path) {
return {}
}
// Scroll to top
return { x: 0, y: 0 }
}
})
I just found an answer for this. Here's my code. The default behaviour will scroll to top, unless you pass a custom params
, which will be ignored by the router if a path
is provided (https://router.vuejs.org/guide/essentials/navigation.html).
scrollBehavior (to, from, savedPosition) {
// savedPosition is only available for popstate navigations.
if (savedPosition) return savedPosition
// if the returned position is falsy or an empty object,
// will retain current scroll position.
if (to.params.savePosition) return {}
// scroll to anchor by returning the selector
if (to.hash) {
let position = {selector: to.hash}
// specify offset of the element
// if (to.hash === '#anchor2') {
// position.offset = { y: 100 }
// }
return position
}
// scroll to top by default
return {x: 0, y: 0}
}
If you return a falsy or an empty object, Vue router will return the original position. Then I will just pass a custom params
which I use by the name of 'savePosition' to params
.
this.$router.push({ query: query, params: { savePosition: true } })
That way, your router by default will scroll to top unless you pass savePosition
to params
, or if you pass a hash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With