NicolasJEngler
NicolasJEngler

Reputation: 565

Vue Router how to scroll to same hash consecutively

I'm currently working on a site based on Vue and using Vue Router for routing. My way to handle scroll behavior to anchor links is the following:

const router = new VueRouter({
    routes,
    scrollBehavior (to) {
        if (to.hash) {
            return { 
                selector: to.hash,
                offset: { x: 0, y: 140 }
            }
        }
        return { x: 0, y: 0 }
    }
})

And my links are built in the following way:

<router-link class="insurance-link d-block" to="#hogar">
    <img class="insurance-logo img-fluid" src="@/assets/home-icon.svg">
    Hogar
</router-link>

If I click on the link for the first time it scrolls to the anchor position fine, but if I scroll back to the top and click on it for the second time it won't scroll back to that position again. If I click on another anchor link and then click on the previous one everything works fine. Any ideas on what might be happening?

Upvotes: 1

Views: 5370

Answers (4)

oehmaddin
oehmaddin

Reputation: 180

Inspired by Owl's answer, this should work out of the box width vue-router 4.4.x

const router = createRouter({/*...*/});

router.beforeEach((to, from, next) => {
    if(to.hash){
        document.querySelector(to.hash)?.scrollIntoView()
    }
    next()
})

Upvotes: 1

NicolasJEngler
NicolasJEngler

Reputation: 565

Given I had limited time (and will, to be honest) to keep on trying solutions I opted to go with vue-anchor-router-link (https://github.com/mperator/vue-anchor-router-link), which worked like a charm. Thank you so much to everyone, your answers helped me understand better the way Vue and Vue Router handle anchor links.

Upvotes: -1

Owl
Owl

Reputation: 6853

The easiest fix is to use <a> instead

<a class="insurance-link d-block" href="#hogar">
    <img class="insurance-logo img-fluid" src="@/assets/home-icon.svg">
    Hogar
</a>

If you want to use <router-link> and make it work on the 2nd time you click on the router-link, you need to add custom onclick handler like this:

<router-link class="insurance-link d-block" to="#hogar" @click.native="scrollToId('hogar')">
    <img class="insurance-logo img-fluid" src="@/assets/home-icon.svg">
    Hogar
</router-link>

and add to your vue methods:

methods: {
  scrollToId(id) {
    document.getElementById(id).scrollIntoView();
  }
}

Upvotes: 2

Noah Stahl
Noah Stahl

Reputation: 7623

I believe this behavior is due to Vue preventing the click event propagation, and when you're already at the clicked hash, the router considers it a non-change so ignores it. Vue docs state:

In HTML5 history mode, router-link will intercept the click event so that the browser doesn't try to reload the page.

Using the router-link default slot is one way to take more control. This seems to provide a workaround:

<router-link to="#hogar" v-slot="{ href }">
    <a :href="href">Hogar</a>
</router-link>

Upvotes: 0

Related Questions