Frederick M. Rogers
Frederick M. Rogers

Reputation: 921

Javascript - mouseover/out event fires on all sibling elements at the same time

I have four sibling elements with a class of "box". I use the getElementsByClassName() with a for loop to iterate over the matching set of elements and use the addEventListener() method to bind a mouseover event to each element.

The problem I am having is when I use .style.display in the event handler, and mouse over any of the matching elements, all of the preceding sibling matching elements change their display values.

If I use a different style method like .style.backgroundColor everything works fine. I have googled and youtubed and I can't find a solution. I would appreciate any and all assistance, thank you.

Code:

function hover(eClass) {
  var elem = document.getElementsByClassName(eClass);
  for (var i=0;i<elem.length;i++) {
    elem[i].addEventListener('mouseover', mouseOver);
    elem[i].addEventListener('mouseout', mouseOut);
  }
  function mouseOver() {    
    //this.style.backgroundColor = 'red';
    this.style.display = 'none';
  }
  function mouseOut() {
    //this.style.backgroundColor = 'grey';
  }  
}
hover('box');

Codepen example

Upvotes: 1

Views: 1339

Answers (3)

kolodi
kolodi

Reputation: 1062

I checked your code. It's fine. In fact, ig you try to hover the last (at the bottom) square, only it will disappear. When you hover the top one, it disappears and next one become the top one, so it disappear too, and so on, until all them disappear. This happen too fast and it seams that all squares disappear at once...

Upvotes: 3

faino
faino

Reputation: 3224

misher beat me to it, but yes that is what's happening. I put 1 - 4 in the DIVs:

<div class="container">
    <div class="box grey">1</div>
    <div class="box grey">2</div>
    <div class="box grey">3</div>
    <div class="box grey">4</div>
</div>

And used the console to catch the innerHTML of the elements and they vanish, which gave me:

1
2
3
4

No surprise there, once the display is set to none, the elements move up as the one you hovered no longer has its CSS in play. You can use visibility to keep that from happening, but the mouseout event will not trigger on invisible elements.

With a bit of tweaking, you can use the data attribute and the mousemove event to keep the elements in place; this will only fire once so if the page re-sizes or moves the X and Y values will be off, perhaps a window.onresize would fix that, but here's this:

function hover(eClass) {
    var elem = document.getElementsByClassName(eClass);
    for (var i = 0; i < elem.length; i++) {
        elem[i].addEventListener('mouseover', mouseOver);
    }
    document.addEventListener('mousemove', mouseMove);
    function mouseOver() {
        var minX = this.offsetLeft;
        var maxX = minX + this.offsetWidth;
        var minY = this.offsetTop;
        var maxY = minY + this.offsetHeight;
        this.setAttribute('data-minx', minX);
        this.setAttribute('data-maxx', maxX);
        this.setAttribute('data-miny', minY);
        this.setAttribute('data-maxy', maxY);
        this.style.visibility = 'hidden';
    }
    function mouseMove(e) {
        e = e || event;
        for(i = 0; i < elem.length; i++) {
            var div = elem[i];
            var minX = div.getAttribute('data-minx');
            var maxX = div.getAttribute('data-maxx');
            var minY = div.getAttribute('data-miny');
            var maxY = div.getAttribute('data-maxy');
            if(e.clientX >= minX && e.clientX <= maxX && e.clientY >= minY && e.clientY <= maxY) {
                // over the Div
            } else {
                div.style.visibility = 'visible';
            }
        }
    }
}

hover('box');

Upvotes: 1

dannyjolie
dannyjolie

Reputation: 11349

This was funny, and it took a while to see that it's just a practical problem. When you hover over the first box, it is removed, and the next one is redrawn in its place. But then the event fires again on box 2, because it is now below the cursor, and so it continues. Of course this happens too fast to see, but it's what's going on. If you really want to remove the element from the browser's draw function, you'll have to figure out something to stop the event firing on the next element, or set opacity: 0.

Update

This is sort of ugly, but removing the event listeners and adding them again demonstrates how this could work. http://codepen.io/dannyjolie/pen/mPmpqE

function mouseOver() {
  //this.style.backgroundColor = 'red';
  removeListeners('box');
  this.style.display = 'none';
  setTimeout(function(){
    addListeners('box');
  }, 100);
}

Upvotes: 2

Related Questions