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");