Vue Router how to scroll to same hash consecutively

此生再无相见时 提交于 2021-02-11 05:59:34

问题


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?


回答1:


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();
  }
}



回答2:


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>



回答3:


This has nothing to do with Vue. If you click on a link setting your hash value to something, you scroll away and then you click on the same link again, the hash value won't change, therefore the browser won't react. No change => no reaction.

In order to fix this you have to bind a @click.native="hashChecker" on each of those links. In that function, check if the event.target.href matches current window.location.hash. If they don't match, skip.

If they match, set window.location.hash to '#' and immediately back to its initial value. This time the window will detect the change and will react to it. That's it, really.

A sample version of that function:

hashChecker(e) {
  if (e.target.href === window.location.hash {
    window.location.hash = '#';
    window.location.hash = e.target.href;
  }
}

Keep in mind this function is a bit simplistic and only covers your case. If your links had full blown urls (including domain, protocol, etc...) you'd need to first extract the hash from them and then match it against current window.location.hash.

You could place this function as a method in the component where you use it. If you use it in more than one place you can put it in a helper file and import it from there. Since it doesn't use this, it can be static or a const.




回答4:


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.



来源:https://stackoverflow.com/questions/63529557/vue-router-how-to-scroll-to-same-hash-consecutively

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!