lache
lache

Reputation: 830

Scroll to section from child component in Vue.js

I am trying to understand how to emit an event from a child component to the parent that scrolls to the correct section via a ref or id. So for example the navigation menu is a child component with links. when I click a link, the corresponding section in the parent scrolls into view. I am coming from React so I am a bit thrown off. How do I pass parameters up to scroll to correct ref or id? basically the way anchorlinks act.

Here is what I got so far.. I am not sure I should be using links , I might need buttons since i'm not navigating pages.

Navigation.vue (Child)

<template>
  <div class="navigation">
    <img class="logo" alt="Vue logo" src="../assets/logo.png" />
    <nav>
      <ul>
        <li>
          <a @click="goSection" href="/">Contact</a>
        </li>
        <li>
          <a href="/">Projects</a>
        </li>
        <li>
          <a href="/">Skills</a>
        </li>
        <li>
          <a href="/">Education</a>
        </li>
      </ul>
    </nav>
  </div>
</template>

<script>
export default {
  name: "Navigation",
  //I want to emit an event in the parent where the page section scrolls in to view//
  methods: {
    goSection() {
      this.$emit("go-section", this.value);
    },
  },
};
</script>

App.vue (Parent)

<template>
  <div id="app">
    <Navigation @go-section="goToSection" />
    
    <section class="section" ref="projects">
      <p>Projects</p>
    </section>
    <section class="section" ref="skills">
      <p>Skills</p>
    </section>
    <section class="section" ref="contact">
      <p>Contacts</p>
    </section>
  </div>
</template>

<script>
import Navigation from "./components/Navigation.vue";
export default {
  name: "App",
  components: {
    Navigation,
  },
  methods: {
    goToSection(event, value) {
      var element = this.$refs[(event, value)];
      var top = element.offsetTop;
      window.scrollTo(0, top);
    },
  },
};
</script>

Upvotes: 1

Views: 6044

Answers (2)

Nikola Pavicevic
Nikola Pavicevic

Reputation: 23480

You can use a tag but prevent default link behavior, and pass ref to your goSection method :

Vue.component('navigation', {
  template: `
    <div class="navigation">
      <img class="logo" alt="Vue logo" src="../assets/logo.png" />
      <nav>
        <ul>
          <li>
            <a @click.prevent="goSection('contact')" href="/">Contact</a>
          </li>
          <li>
            <a href="#" @click.prevent="goSection('projects')">Projects</a>
          </li>
          <li>
            <a href="#" @click.prevent="goSection('skils')">Skills</a>
          </li>
          <li>
            <a href="#" @click.prevent="goSection('contact')">Education</a>
          </li>
        </ul>
      </nav>
    </div>
  `,
   methods: {
    goSection(val) {
      this.$emit("go-section", val);
    },
  },
})

new Vue({
  el: '#demo',
  methods: {
    goToSection(value) {
      const top = this.$refs[(value)].offsetTop;
      window.scrollTo({
        top: top,
        left: 0,
        behavior: 'smooth'
      });
    },
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <navigation @go-section="goToSection"></navigation>
  <section class="section" ref="projects">
    <p>Projects</p>
  </section>
  <section class="section" ref="skills">
    <p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p><p>Skills</p>
  </section>
  <section class="section" ref="contact">
    <p>Contacts</p>
  </section>
</div>

Upvotes: 1

Romalex
Romalex

Reputation: 1819

You can emit an event with parameter (section ref for example) in the child component:

<a @click="$emit('go-section', 'contact')" href="/">Contact</a>
<a @click="$emit('go-section', 'projects')" href="/">Projects</a>

And then use this parameter in the parent's listener method

// template
<Navigation @go-section="goToSection" />

// js
goToSection(sectionRef) {
  var element = this.$refs[sectionRef];
  var top = element.offsetTop;
  window.scrollTo(0, top);
},

Upvotes: 1

Related Questions