Home > Enterprise >  Get child element from element through an event with Vue
Get child element from element through an event with Vue

Time:02-14

Goal

What I'm trying to achieve is that whenever the user clicks on the .menu-item element, the dropdown element .menu-item-dropdown will get a class that will show the element.

Problem

Currently, when I click on the .menu-item class element, the returned value from the console.log in showMobileNavDropdown() returns null. When clicking, the event.target element is .menu-item-main and not .menu-item. This happens only when I click on the text of the li. Otherwise this works as intended.

What would be the best way to include the li text so that I can still grab the .menu-item-dropdown class?

Vue

<template>
    <div>
        <nav >
            <div >
                <img  src="/images/logo.svg" alt="" />
            </div>
            <div >
                <ul >
                    <li
                        
                        @click="showMobileNavDropdown($event)"
                    >
                        <!-- Main Title On Nav -->
                        <a  href="#">Company</a>

                        <!-- Dropdown -->
                        <div >
                            <ul>
                                <li >
                                    <a href="">About</a>
                                </li>
                                <li >
                                    <a href="">Contact</a>
                                </li>
                            </ul>
                        </div>
                    </li>
                </ul>
            </div>

            <div >
                <a href="" >Contact us</a>
            </div>

            <div  @click="openMobileNav">
                <span ></span>
                <span ></span>
            </div>
        </nav>

        <div ></div>
    </div>
</template>

<script>
export default {
    methods: {
        openMobileNav() {
            var mobileNav = document.querySelector(".mobile-nav");
            mobileNav.classList.toggle("showMobileNav");
        },

        // This function
        showMobileNavDropdown(event) {
            console.log(event); // This element returns 'menu-item-main' and not 'menu-item'
            console.log(event.target.querySelector(".menu-item-dropdown"));
        },
    },
};
</script>

CodePudding user response:

Assuming you have a longer list of possible click-targets and can't or won't just use refs, I would use event-delegation and in the click-handler check, whether the clicked element is inside a clickable parent and based on that, toggle a class on the parent, which can then be used to select the child in CSS, for example to change it's opacity.

Vue.component('foo-bar', {      
  methods: {
    toggleSubItemVisibility({ target }) {
      const item = target.closest('.nav-item');
      // we check because the user might have clicked on the surrounding ul
      if (item) {
        item.classList.toggle('active');
      }
    }
  },
  template: `
  <nav>
    <ul @click="toggleSubItemVisibility">
      <li >
        <span >Foo</span>
        <div >More details...</div>
      </li>
      <li >
        <span >Bar</span>
        <div >More details...</div>
      </li>
    </ul>  
  </nav>`
})

new Vue({
  el: '#app'
});
nav ul { 
  list-style-type: none;
  display: flex;
  flex-direction: row;
  gap: 12px;
}

.nav-label {
  cursor: pointer;
}

.nav-sub-item {
  opacity: 0;
  transition: opacity 1s ease;
}

.nav-item.active .nav-sub-item {
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<foo-bar></foo-bar>
</div>

CodePudding user response:

The solution was to either grab the element, and if that returned null, grab the sibling. This way, it's always possible to select the .menu-item-dropdown element. When clicking on the element, it can either be a child or sibling.

Part of Solution

var element =
        event.target.querySelector(".menu-item-dropdown") ||
        event.target.nextElementSibling;

element.classList.toggle("hide_drop");
  • Related