talaash
talaash

Reputation: 77

How to scroll to a specific anchor using a router-link?

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

Answers (2)

The Jared Wilcurt
The Jared Wilcurt

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

Jacob Goh
Jacob Goh

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

Related Questions