问题
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