Je cherche un moyen intelligent de gérer les ancres dans la page avec Vue Router. Considérer ce qui suit:
<router-link to="#app">Apply Now</router-link>
<!-- some HTML markup in between... -->
<div id="app">...</div>
Le comportement "scroll to anchor" décrit dans la documentation fonctionne bien sauf que:
div id="app"
. Maintenant, faites défiler la div
vers l’ancre et essayez de cliquer à nouveau dessus - cette fois, vous non sauterez dans la div
. En fait, l'ancre conservera la classe router-link-active
et l'URL contiendra toujours le hash /#app
;Cela est très regrettable du point de vue de l'expérience utilisateur car un client potentiel doit faire défiler manuellement à nouveau pour atteindre la section de l'application.
Je me demandais si Vue Router couvrait cette situation. Pour référence, voici mon routeur:
export default new VueRouter({
routes,
mode: 'history',
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return { selector: to.hash }
} else if (savedPosition) {
return savedPosition;
} else {
return { x: 0, y: 0 }
}
}
})
Je n'ai rien trouvé dans les ressources pour résoudre votre problème, mais vous pouvez utiliser le $route.hash
dans votre hook mounted
du composant qui contient votre <router-view></router-view>
pour résoudre le problème de l'actualisation.
<script>
export default {
name: 'app',
mounted: function()
{
// From testing, without a brief timeout, it won't work.
setTimeout(() => this.scrollFix(this.$route.hash), 1),
},
methods: {
scrollFix: function(hashbang)
{
location.href = hashbang;
}
}
}
</script>
Ensuite, pour résoudre le problème des seconds clics, vous pouvez utiliser le modificateur native
et le lier à votre <router-link></router-link>
. C'est un processus assez manuel mais qui fonctionnera.
<router-link to="#scroll" @click.native="scrollFix('#scroll')">Scroll</router-link>
Il est également possible que vous utilisiez la méthode afterEach
du routeur, mais que vous ne l'ayez pas encore trouvée.
J'ai utilisé cette solution:
<router-link to="/about" @click.native="scrollFix('#team')" >The team</router-link>
Et ça:
methods: {
scrollFix: function(hash) {
setTimeout(() => $('html, body').animate({
scrollTop: $(hash).offset().top
}, 1000), 1)
}
}
Solution possible qui est plus résiliente OMI:
this.$router.Push({ name: 'home' }, undefined, () => { location.href = this.$route.hash })
Comme le 3ème argument est la fonction abort (), il peut avoir des effets secondaires indésirables.
Si vous souhaitez l’utiliser globalement, ajoutez une fonction à votre routeur:
pushWithAnchor: function (routeName, toHash) {
const fromHash = Router.history.current.hash
fromHash !== toHash || !fromHash
? Router.Push({ name: routeName, hash: toHash })
: Router.Push({ name: routeName, hash: fromHash }, undefined, () => { window.location.href = toHash })
}
Et l'utiliser dans des composants avec:
this.$router.options.pushWithAnchor('home', '#fee-calculator-section')
Dans un modèle, vous pouvez faire quelque chose comme:
<a @click="this.$router.options.pushWithAnchor('home', '#fee-calculator-section')"></a>
Malheureusement, vous ne pouvez pas utiliser un décalage de défilement bien
Si vous êtes déjà sur la route avec le hachage, vous pouvez simplement le configurer pour faire défiler jusqu'à la cible.
(notez également que la méthode scrollBehavior()
de votre routeur ne sera pas appelée si vous êtes déjà sur l’itinéraire que vous essayez de suivre).
export default {
methods: {
anchorHashCheck() {
if (window.location.hash === this.$route.hash) {
const el = document.getElementById(this.$route.hash.slice(1))
if (el) {
window.scrollTo(0, el.offsetTop)
}
}
},
},
mounted() {
this.anchorHashCheck()
},
}
Ajoutez ensuite un @click.native
pour écouter les événements sur l’ancre dans votre <router-link>
,
<router-link :to="{hash: '#some-link'}" @click.native="anchorHashCheck">
Some link
</router-link>