How to handle anchors (bookmarks) with Vue Router?

I haven't found anything in the resources to solve your issue but you could utitlize the $route.hash in your mounted hook of the component that holds your <router-view></router-view> to solve the refresh issue.

<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.hash = hashbang;
    }
  }
}
</script>

Then to solve the issue of second clicks you could use the native modifier and bind to your <router-link></router-link>. It's a fairly manual process but will work.

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

There may also be something you could do with the router's afterEach method but haven't figured that out yet.


Possible solution which is more resusable IMO:

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

As the 3rd argument is the abort() function, it may have unwanted side effects though..

If you want to use it globally, add a function to your Router:

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

And use it in components with:

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

Within a template you could do something like:

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

Sadly you cant use a scroll offset though


If you're already on the route with the hash, you can just set it to scroll to the target.

(also note scrollBehavior() method in your router won't get called if you're already on the route you're trying to go to).

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

Then add a @click.native to listen to events on the anchor in your <router-link>,

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