Search code examples
javascriptvue.jsvuejs3event-bubbling

Prevent Mouseenter bubbling in an unorderest list of links in Vue 3


I have tried a lot of different things trying to stop event bubbling on the mousenter event but still have the problem, when I hover on a link the event triggers for all the links, like all of them were hovering at the same time. Is an unordered list of links and I'm using a computed value to dynamically change the inline styles when I hover the links:

My component is something like this:

      <section class="categoryList">
        <ul>
          <li v-for="category in categories" :key="category.id">
            <a
              @mouseenter.stop="mouseOver()"
              @mouseleave.stop="mouseOver()"
              class="category"
              :style="getStyle"
              href="#"
              @click.prevent="getCategory(category.name)"
              >{{ category.name }}</a
            >
          </li>
        </ul>
      </section>

And this is the computed value:

const getStyle = computed(() => {
  if (props.primaryColor != undefined && props.primaryColor != "") {
    if (!hover.value) {
      return `background-color:${props.primaryColor};color:${props.secondaryColor}`;
    } else {
      return `background-color:${props.secondaryColor};color:${props.primaryColor}`;
    }
  } else {
    if (!hover.value) {
      return `background-color:#614EFB;color:white`;
    } else {
      return `background-color:#523dfa;color:white`;
    }
  }
});

And then a standard function to control the hover state dynamically:

function mouseOver() {
  hover.value = !hover.value;
}

Solution

  • If I understood you correctly try to set hover as id instead of boolean:

    const { ref, computed } = Vue
    const app = Vue.createApp({
      setup()  {
        const props = ref({primaryColor: null, secondaryColor: null})
        const categories = ref([{id: 1, name: 'aaa'}, {id: 2, name: 'bbb'}, {id: 3, name: 'ccc'}])
        const hover = ref(null)
        function mouseOver(id) { hover.value = id; }
        function mouseExit() { hover.value = null }
        getCategory = () => {}
        const getStyle = (id) => {
          if (props.primaryColor != undefined && props.primaryColor != "") {
            if (id !== hover.value) {
              return `background-color:${props.primaryColor};color:${props.secondaryColor}`;
            } else {
              return id === hover.value && `background-color:${props.secondaryColor};color:${props.primaryColor}`;
            }
          } else {
            if (id !== hover.value) {
              return `background-color:#614EFB;color:white`;
            } else {
              return `background-color:red;color:white`;
            }
          }
        };
        return { props, categories, mouseOver, getStyle, getCategory, hover, mouseExit }
      }
    })
    app.mount('#demo')
    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
    <div id="demo">
      <section class="categoryList">
      <ul>
        <li v-for="category in categories" :key="category.id">
          <a
            @mouseenter="mouseOver(category.id)"
            @mouseleave="mouseExit()"
            class="category"
            :style="getStyle(category.id)"
            href="#"
            @click.prevent="getCategory(category.name)"
            >{{ category.name }}</a
          >
        </li>
      </ul>
      {{hover}}
    </section>
    </div>