web-dev-qa-db-fra.com

Comment gérer les ancres (signets) avec Vue Router?

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:

  • Lorsque vous cliquez sur l'ancre, cela vous ramène au 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;
  • Avec les étapes ci-dessus, si vous actualisez la page (l'URL contiendra toujours le hachage) et cliquerez sur l'ancre, rien ne se passera non plus.

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 }
        }
    }
})
8
Alex

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.

4
Steven B.

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)
    }
  }
1
Falcoa

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

1
Valentin Rapp

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>
0
wadclapp