Reputation: 77
I'm trying to develop a simple website using vue js and so far it goes well but I'm facing the following Issue:
I'm using a router to change pages, it works, but what I need to do is: Change Page & scroll to a specific anchor.
What I tried already:
Works well: Route to contact page or home
<router-link to="/contact">Contact</router-link>
<router-link to="/">Home</router-link>
Doesn't work:
<router-link :to="{ name: '/', hash: '#technology' }" >Technology</router-link>
The last one works only if I'm on the home page, but whenever I change to Contact Page and try to route to "/#technology" it won't work. It does try routing to "http://example.com/contact/#technology" instead of "http://example.com/#technology".
If I do it like that, it will just scroll to top, but not to the anchor:
<router-link to="/#technology" Technology</router-link>
My Router Code:
const routes = [
{ path: '/', component: Home },
{ path: '/contact', component: Contact }
]
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
if (to.hash) {
return { selector: to.hash };
}
return { x: 0, y: 0 }
},
});
new Vue({
router,
}).$mount('#app');
And the templates look like this ( I did remove the unnecessary code):
<template id="home">
<div>
Home
<div id="technology"> <!-- IT SHOULD SCROLL TO HERE -->
</div>
</template>
<template id="contact">
<div>
Contact Page
</div>
</template>
Upvotes: 4
Views: 8506
Reputation: 343
Using Vue 3 + Vue-Router 4, this worked for me:
function scrollBehavior (to, from, savedPosition) {
// check that path is different, so this doesn't scroll to top every time
// a query parameter is changed
if (to.path !== from.path) {
if (
// if this is a push/pop state (forward/back), use the saved position
savedPosition ||
(
// don't change screen position when closing/opening a modal
to.meta?.savePosition ||
to.params?.savePosition
)
) {
return savedPosition;
}
// If the url has a #sub-section scroll to there
if (to.hash) {
return { el: to.hash, top: 20 };
}
// otherwise always scroll to the top of the page
return new Promise((resolve) => {
// Resolving a promise is needed for some async routes.
// Has no negative impact on synchronous routes.
resolve({ left: 0, top: 0 });
});
}
}
The 20
is an offset, if you set it to 0
it will be right on the element with the ID, if you set it to 300
then the element will be visible 300 pixels below the top of the visible area.
Bonus, it works with name
, so you don't need to use path
.
<RouterLink
:to="{
name: 'routeName',
hash: '#my-hash'
}"
>
Link
</RouterLink>
Upvotes: 0
Reputation: 20845
i think you are on the right path.
but maybe you have mistaken the usage of Route name
and path
.
instead of
<router-link :to="{ name: '/', hash: '#technology' }" >Technology</router-link>
try using path
instead of name
<router-link :to="{ path: '/', hash: '#technology' }" >Technology</router-link>
Upvotes: 9