[Vuejs]-Vue 3 how to implement intersection observer for multiple element to create an active menu pointing to the element on the view port

0👍

If I want to give you advice, please use vuex (or pinia for version 3).

But any way, if you insist to do it like that, there is no problem.

You have to add some ids to make InfoSteps unique. there:

Child Component:

<template>
  <div :ref="infoStepRef">
    <h3>{{ infoStepRef }}</h3>
  </div>
</template>

<script>
export default {
  name: "InfoStep",
  props: {
    infoStepRef: {
      type: String,
      required: true,
    },
  },
  emits: ["on-step-intersection"],
  data: () => {
    return {
      isInfoStepIntersecting: false,
    };
  },
  watch: {
    isInfoStepIntersecting: function (value) {
      this.$emit("on-step-intersection", { name: this.infoStepRef, value });
    },
  },
  mounted() {
    const stepRef = this.$refs[this.infoStepRef];
    const handler = (entries) => {
      this.isInfoStepIntersecting = entries[0].isIntersecting;
    };
    const observer = new window.IntersectionObserver(handler);
    observer.observe(stepRef);
  },
};
</script>

and in parent:

<template>
  <div>
    <div class="info-steps">
      <span :class="{ 'active': stepOne }">Span 1</span>
      <span :class="{ 'active': stepTwo }">Span 2</span>
      <!-- add more spans as needed -->
    </div>
    <InfoStep info-step-ref="Step One" @on-step-intersection="handleActiveStep" />
    <InfoStep info-step-ref="Step Two" @on-step-intersection="handleActiveStep" />
    <!-- add more InfoStep components as needed -->
  </div>
</template>

<script>
export default {
  data: () => {
    return {
      stepOne: false,
      stepTwo: false,
      // add more steps as needed
    };
  },
  methods: {
    handleActiveStep({ name, value }) {
      switch(name) {
        case "Step One":
          this.stepOne = value;
          break;
        case "Step Two":
          this.stepTwo = value;
          break;
        // handle more steps as needed
      }
    },
  },
};
</script>

<style scoped>
.active {
  font-weight: 600;
  color: cadetblue;
}
</style>

as you see, a switch satement used to update the data. also handleActiveStep is used to handle active InfoStep.

Hope Helps! 🌷

Leave a comment