it-swarm.com.de

Wie gehe ich mit Vue Router vor Anker (Lesezeichen)?

Ich suche nach einer intelligenten Methode, um mit Vue Router In-Page-Anker zu behandeln. Folgendes berücksichtigen:

<router-link to="#app">Apply Now</router-link>
<!-- some HTML markup in between... -->
<div id="app">...</div>

Das Verhalten "zum Anker scrollen" in den Dokumenten beschrieben funktioniert gut, mit Ausnahme:

  • Wenn Sie auf den Anker klicken, gelangen Sie zum div id="app". Scrollen Sie nun von der div zurück zum Anker und versuchen Sie erneut, darauf zu klicken. Diesmal springen Sie nicht zur div. Tatsächlich behält der Anker die Klasse router-link-active bei, und die URL enthält immer noch den Hash /#app;
  • Wenn Sie die Seite mit den oben genannten Schritten aktualisieren (die URL enthält immer noch den Hash) und auf den Anker klicken, passiert auch nichts.

Dies ist aus UX-Sicht sehr ungünstig, da ein potenzieller Kunde manuell ganz nach unten scrollen muss, um den Anwendungsbereich zu erreichen.

Ich habe mich gefragt, ob Vue Router diese Situation abdeckt. Als Referenz hier mein Router:

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

Ich habe nichts in den Ressourcen gefunden, um Ihr Problem zu lösen, aber Sie könnten den $route.hash in Ihrem mounted-Hook der Komponente verwenden, die Ihren <router-view></router-view> enthält, um das Aktualisierungsproblem zu lösen.

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

Um das Problem der zweiten Klicks zu lösen, können Sie den Modifizierer native verwenden und an Ihren <router-link></router-link> binden. Es ist ein ziemlich manueller Prozess, wird aber funktionieren.

<router-link to="#scroll" @click.native="scrollFix('#scroll')">Scroll</router-link>

Möglicherweise gibt es auch etwas, was Sie mit der afterEach-Methode des Routers tun könnten, aber das noch nicht herausgefunden haben.

4
Steven B.

Ich habe diese Lösung verwendet:

<router-link to="/about" @click.native="scrollFix('#team')" >The team</router-link>

Und das:

methods: {
    scrollFix: function(hash) {
      setTimeout(() => $('html, body').animate({
      scrollTop: $(hash).offset().top
      }, 1000), 1)
    }
  }
1
Falcoa

Mögliche Lösung, die IMO wiederverwendbar ist:

this.$router.Push({ name: 'home' }, undefined, () => { location.href = this.$route.hash })

Da das dritte Argument die Funktion abort () ist, kann es jedoch unerwünschte Nebenwirkungen haben.

Wenn Sie es global verwenden möchten, fügen Sie Ihrem Router eine Funktion hinzu:

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

Und verwenden Sie es in Komponenten mit:

this.$router.options.pushWithAnchor('home', '#fee-calculator-section')

Innerhalb einer Vorlage könnten Sie Folgendes tun:

<a @click="this.$router.options.pushWithAnchor('home', '#fee-calculator-section')"></a>

Leider kann man keinen Scroll-Offset verwenden

1
Valentin Rapp

Mir ist klar, dass Sie nach Ankern gefragt haben und bereits eine Antwort haben. Die folgende Funktion sollte jedoch sowohl für Anker als auch für reguläre Links funktionieren. Hiermit können Sie zur Position der ersten Instanz der Komponente scrollen, der eine Route zugeordnet wurde. Ich habe es geschrieben, um zu sehen, ob ich mithilfe eines Hashs das Scrollen im Anker-Stil umgehen kann.

scrollBehavior(to, from, savedPosition) {
if (to.matched) {
  const children = to.matched[1].parent.instances.default.$children;
  for (let i = 0; i < children.length; i++) {
    let child = children[i];
    if (child.$options._componentTag === to.matched[1].components.default.name) {
      return {
        x: child.$el.offsetLeft,
        y: child.$el.offsetTop
      };
    }
  }
}
return {
  x: 0,
  y: 0
};
}

Der Grund, warum ich parent.instances Verwende, ist, dass der Wert to.matched[1].instances Leer ist. Es ist nicht die eleganteste Lösung, obwohl es jemand anderem da draußen helfen könnte.

Hinweis: Dies funktioniert nur, wenn Sie die erste Instanz einer Komponente scrollen möchten.

0
Byebye

Wenn Sie bereits mit dem Hash auf der Route sind, können Sie ihn so einstellen, dass er zum Ziel blättert.

(Auch die scrollBehavior()-Methode in Ihrem Router wird nicht aufgerufen, wenn Sie sich bereits auf der Route befinden, die Sie zu erreichen versuchen).

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

Fügen Sie dann einen @click.native hinzu, um Ereignisse auf dem Anker in Ihrem <router-link> zu hören.

<router-link :to="{hash: '#some-link'}" @click.native="anchorHashCheck">
  Some link
</router-link>
0
wadclapp