38

I'm developing a Vue.js application and I'm having trouble to link an anchor to a certain div within a component.

I have the following anchor:

<a href="#porto" class="porto-button">Porto, Portugal</a>

and the following div:

<div id="porto" class="fl-porto">

I'm using vue-router in hash mode.

The problem is, whenever I click the "porto-button" it will redirect me to the "home" page ( ' / ' )

I'm using Vue.js 1.X and I tried using history mode (URL without the hashbang) but it gives me a cannot GET '/page' error upon refreshing a page.

Am I doing something wrong? What can I do about this?

7
  • I think just take the '#' out of your id? Should just be <div id="porto" class="fl-porto">, no? Commented Mar 7, 2017 at 11:35
  • I did that but to no avail. That's the first thing I tried to do actually but I am up to anything at this point. (I'll edit the question nonetheless) Commented Mar 7, 2017 at 11:38
  • Put a named anchor tag inside your div? <a name="porto">, then your a href="#porto"> should work. Commented Mar 7, 2017 at 11:58
  • Ah sorry I didn't see you were in hash mode. If you switch to history mode, it should work, but you'll need a catchall route, per: router.vuejs.org/en/essentials/… Commented Mar 7, 2017 at 12:07
  • I tried using history mode too. However, the link breaks with cannot GET /page whenever I refresh the page I am in Commented Mar 7, 2017 at 14:23

5 Answers 5

52

Because you are using router in hash mode, you will not be able to scroll that easily because scrolling to /#something will actually redirect you to 'something' page.

You will have to emulate scrolling behaviour on your own, try doing something like that:

//P.S. the code is written for Vue 2.
//You will have to adjust it to Vue 1.

//Your view:
<a class="porto-button" @click="scrollMeTo('porto')">Porto, Portugal</a>
...
<div ref="porto" class="fl-porto">
//Your code:
methods: {
  scrollMeTo(refName) {
    var element = this.$refs[refName];
    var top = element.offsetTop;

    window.scrollTo(0, top);
  }
}

How it works:

  1. Set the references through ref attribute to the element you would like to scroll to;
  2. Write a function that will programmatically set window.scrollY to the top of the referenced element.
  3. Job is done :)

Update 1:

jsfiddle https://jsfiddle.net/5k4ptmqg/4/

Update 2:

Seems that in Vue 1 ref="name" looked like el:name (docs), here is an updated example:

https://jsfiddle.net/5y3pkoyz/2/

Sign up to request clarification or add additional context in comments.

5 Comments

I'm trying to recreate this. It is not working. Is this compatible with Vue 1.X or is it exclusive to Vue 2.X??
it is not exclusive to vue2, create jsfiddle with your tryings @fmlopes
It really seems to be something related to the Vue build version. Because it works when using 2.0.1 and not with 1.0.7. jsfiddle.net/frankml/5y3pkoyz/1 The button press returns "element is undefined"
@fmlopes have added a new example for vue 1 (Update 2). Does it work for you?
Yes, it does. This is the correct answer. I tried in the 1.X build and it worked. Then updated to the 2.X build and it worked as well.
19

Another method is to use "scrollIntoView()"

So, euvl's code still stands, except you would change the method slightly:


    new Vue({
      el: '#app',
      methods: {
        goto(refName) {
            var element = this.$els[refName];
          element.scrollIntoView();
        }
      }
    })

If you wanted to get fancy and make the scroll smooth, you can even add the following:

element.scrollIntoView({ behavior: 'smooth' });

Note that this will need a polyfill for older browsers.

1 Comment

In VueJS 2 replace this.$els with this.$refs to make this work.
12

What worked for me

<router-link to="#leaders">Leaders</router-link>

or dynamic

<router-link :to="`#${subMenuItem.linkTarget}`" class="page-submenu-list__link">
                    {{subMenuItem.linkTitle}}
                </router-link>

in router

routes:[],
scrollBehavior (to, from, savedPosition) {
    //https://router.vuejs.org/guide/advanced/scroll-behavior.html
    if (to.hash) {
            return { selector: to.hash }
        } else if (savedPosition) {
            return savedPosition;
        } else {
            return { x: 0, y: 0 }
        }
  }

1 Comment

This only seems to work the first time - if I scroll up and click again it does not scroll me down to the correct div
4

An alternative solution is to use the v-scroll-to directive (webpage, github). I find this solution to be clean, simple, flexible and effective. To use:

  1. Install it:

    npm install --save vue-scrollto
    
  2. Have Vue 'use' it:

    var VueScrollTo = require('vue-scrollto');
    Vue.use(VueScrollTo)
    
  3. Apply it as a directive in your Vue component's template:

    <a href="#" v-scroll-to="'#element'">Scroll to #element</a>
    
    <div id="element">
      Hi. I'm #element.
    </div>
    
  4. Or apply it programmatically in your Vue component's methods:

    this.$scrollTo('#element', 500, { easing: 'ease-in-out' })
    
  5. Or apply it programmatically in your Vuex actions:

    import { scrollTo } from 'vue-scrollto'
    
    scrollTo('#element', 500, { easing: 'ease-in-out' })
    

Another solution, if you're already using Vuetify, you may prefer to use Vuetify's built-in programmatic scrolling method, $vuetify.goTo():

<v-btn @click="$vuetify.goTo('#element', {duration: 500, easing: 'easeInOutCubic'})">
  Scroll to #element
</v-btn>

<div id="element">
  Hi. I'm #element.
</div>

1 Comment

Thank you for this solution. vue-scrollto didn't do what i expected it to but the vuetify solution was the magic
3

If you set a ref="something" on an element, you could also use this oneliner with @click:

<a @click="$refs.something.$el.scrollIntoView()">
    Go to something
</a>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.