Vue router navigation to the same route fails

Viewed 1098

Code snippet can be found in this jsfiddle, sorry for posting code externally, stackoverflow code block always returns a Server Error in '/' Application when I click the navigation links.

Steps to reproduce my problem:

  1. Click on Foo
  2. Click Foo-3
  3. Scroll up
  4. Repeat step 2

The expected behaviour is to scroll down to Foo-3, like the first time, but it actually stays at the same position and doesn't scroll to Foo-3.

How can I force it to scroll to Foo-3 if I click Foo-3 first and scroll up and click Foo-3 again in this case?

Thanks in advance.

EDIT: Code snippet didn't work in stackoverflow because of the path error in stackoverflow, please refer to js fiddle link I posted. I didn't create this code, but I am having the exactly same issue here. I didn't find the solution on Github, so I come here to ask for help. If there are any issues, please shout out.

Code credit

Original question in Github

var FooComponent = {
  template: '#foo-template'
};
var routes = [{
  path: '/foo',
  component: FooComponent
}];
var scrollBehavior = function(to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash
    }
  } else {
    return {
      x: 0,
      y: 0
    }
  }
};
var router = new VueRouter({
  routes: routes,
  scrollBehavior: scrollBehavior,
  mode: 'history'
});
var app = new Vue({
  el: '#app-root',
  router: router
});
<div id="app-root">
  <h1>Issue Reproduction</h1>
  <router-link to="/foo">Foo</router-link>
  <h2>Nav</h2>
  <router-view></router-view>
</div>
<script type="text/x-template" id="foo-template">
  <section>
    <router-link :to="{path: '/foo', hash: 'foo-1'}">Foo-1</router-link>
    <router-link :to="{path: '/foo', hash: 'foo-2'}">Foo-2</router-link>
    <router-link :to="{path: '/foo', hash: 'foo-3'}">Foo-3</router-link>
    <h2 id="foo-1">Foo-1</h2>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <h2 id="foo-2">Foo-2</h2>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <h2 id="foo-3">Foo-3</h2>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <p>???</p>
    <p>???</p>
  </section>
</script>

1 Answers

It is usual when using fragment identifiers, not limited to Vue.js. You can resolve this problem by altering the hash. Here's a simple demo in which the issue will not be reproduced.

In the demo, I added a listener in order to listen to scroll event and let the hash change based on the last element went through.

I hope it can give you a hint.

var FooComponent = {
  template: '#foo-template',
  mounted() {
    const switchHash = () => {
     Array.from(document.querySelectorAll('h2')).forEach(h2 => {
       if(h2.offsetTop < window.pageYOffset && h2.offsetTop + h2.clientHeight > window.pageYOffset) {
         window.location.hash = h2.id;
       }
     });
    };
    window.addEventListener('scroll', switchHash);
  }
};
Related