0

I have a mouseover and mouseleave event listener on the same elements, when you mouseover it adds a class and mouseleave removes the class.

I am running a forEach so that when you mouseover a specific item it shows a specific block of text for that item. That's why I'm using JS and not plain CSS.

I was looking for a way to optimize the following piece of code, please.

const pageNavRings = document.querySelectorAll('.page-nav-ring')

pageNavRings.forEach((pageRing) => {
  pageRing.addEventListener('mouseover', (e) => {
    const pageRingParent = e.target.closest('.page-nav__list--item')
    pageRingParent.querySelector('.page-nav-label').classList.add('is-visible')
  })

  pageRing.addEventListener('mouseleave', (e) => {
    const pageRingParent = e.target.closest('.page-nav__list--item')
    pageRingParent.querySelector('.page-nav-label').classList.remove('is-visible')
  })
})

Seems like this piece of code can be written better and more DRY. All and any help would be much appreciated.

KD1
  • 107
  • 1
  • 15
  • `classList` has a `toggle` method that might help... – Heretic Monkey Feb 08 '18 at 15:23
  • More code is less code. Declare the functions instead of creating a ton of similar functions in a loop. Check also if it's possible to reduce event listeners by using event delegation. – Teemu Feb 08 '18 at 15:27

3 Answers3

1

My attempt to make it more compact and clear. Not sure about your html, so used parentElement to get label.

    const rings = document.querySelectorAll('.page-nav-ring')

    rings.forEach((ring) => {
        const label = ring.parentElement.querySelector('.page-nav-label');
        ring.addEventListener('mouseover', () => { label.classList.add("is-visible") });
        ring.addEventListener('mouseleave', () => { label.classList.remove("is-visible") });
    });
soeik
  • 905
  • 6
  • 15
0

I'd solve this without using JavaScript but CSS:

.page-nav-ring > .page-nav__list--item {
   opacity: 1;
}
.page-nav-ring > .page-nav__list--item:hover {
   opacity: 0.1;
}
<ul class="page-nav-ring">
  <li class="page-nav__list--item">Hello World</li>
  <li class="page-nav__list--item">Hello World 2</li>
  <li class="page-nav__list--item">Hello World 3</li>
</ul>

No more JS needed. Of course you can change the opacity attribute to the attributes you need.

messerbill
  • 5,499
  • 1
  • 27
  • 38
0
const pageNavRings = document.querySelectorAll('.page-nav-ring')

pageNavRings.forEach(pageRing => {
  // Move everything into `handler` function
  // to make use of scoping (you will see why later)
  pageRing.addEventListener('mouseover', handler);
})

function handler(e){
  // Cache these values using variable
  const className = 'is-visible';
  const pageRingParent = e.target.closest('.page-nav__list--item')
  const pageRingLabel = pageRingParent.querySelector('.page-nav-label');

  pageRingLabel.classList.add(className);

  // Add `mouseleave` event listener in this handler is fine
  // Because it doesn't need to listen to this event
  // before everything started anyway
  this.addEventListener('mouseleave', e => {
    // Using the values from the const above,
    // You don't have to use `e.target.closest` and `querySelector` again
    pageRingLabel.classList.remove(className);
  });
}
yqlim
  • 6,898
  • 3
  • 19
  • 43