How to handle bindings (bookmarks) using Vue Router?

I am looking for a smart way to handle anchors on a page using Vue Router. Consider the following:

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

The “scroll to anchor” behavior described in the documentation works fine, except for:

  • When you click on the anchor, it leads you to div id="app". Now scroll from divback to anchor and try clicking it again - this time you will not jump down to div. In fact, the anchor will save the class router-link-active, and the URL will still contain a hash /#app;
  • Using the steps above, if you refresh the page (the URL will still have a hash) and click on the anchor, nothing will happen.

This is very unfortunate from a UX point of view, because the potential customer must manually scroll all the way down again to get to the application section.

I was wondering if Vue Router covers this situation. For reference, here is my 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
source share
5 answers

I did not find anything in the resources to solve your problem, but you can use the component that yours contains $route.hashin your hook to solve the update problem.mounted<router-view></router-view>

<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 problem of repeated clicks, you can use the modifier nativeand bind it to <router-link></router-link>. This is a fairly manual process, but it will work.

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

-, router afterEach, .

+5

, :

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

abort(), , ..

, :

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

:

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

- :

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

, ,

+2

, .

( , scrollBehavior() , , ).

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

@click.native <router-link>,

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

:

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

:

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

, , . , . , . , , , , .

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

, parent.instances, , to.matched[1].instances . , - .

. , .

0
source

Source: https://habr.com/ru/post/1681830/


All Articles