Reputation: 16845
I need to show an HTMLElement
when hovering the mouse on an element (trigger) and hiding it when leaving the same element.
Here the shown/hidden element is not hovering the trigger element.
var div = document.createElement("div");
div.className = "d";
document.body.appendChild(div);
var hov = document.createElement("div");
hov.className = "h";
var hover = false;
var overEvent = "mouseenter";
var overOut = "mouseleave";
div.addEventListener(overEvent, function(e) {
if (hover) return;
document.body.appendChild(hov);
hover = true;
console.log("OVER");
});
div.addEventListener(overOut, function(e) {
if (!hover) return;
document.body.removeChild(hov);
hover = false;
console.log("OUT");
});
.d {
width: 100px;
height: 100px;
background-color: #ff9900;
z-index: 0;
}
.h {
width: 100px;
height: 100px;
top: 150px;
bottom: 150px;
background-color: #000000;
opacity: 0.5;
z-index: 1;
}
div {
position: absolute;
}
Here, the trigger is covered and things work strange:
var div = document.createElement("div");
div.className = "d";
document.body.appendChild(div);
var hov = document.createElement("div");
hov.className = "h";
var hover = false;
var overEvent = "mouseenter";
var overOut = "mouseleave";
div.addEventListener(overEvent, function(e) {
if (hover) return;
document.body.appendChild(hov);
hover = true;
console.log("OVER");
});
div.addEventListener(overOut, function(e) {
if (!hover) return;
document.body.removeChild(hov);
hover = false;
console.log("OUT");
});
.d {
width: 100px;
height: 100px;
background-color: #ff9900;
z-index: 0;
}
.h {
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.5;
z-index: 1;
}
div {
position: absolute;
}
In this case, I can see that the listeners are called repeatedly when moving the mouse on top of the trigger element, causing this funny intermittent undesired effect of the overlay to be placed and removed many times.
This happens also when using mouseover
and mouseout
as events.
Why is this happening?
Upvotes: 0
Views: 908
Reputation:
Assuming hov
follows div
in DOM order, you can control its visibility with CSS.
var div = document.createElement("div");
div.className = "d";
document.body.appendChild(div);
var hov = document.createElement("div");
hov.className = "h";
document.body.appendChild(hov);
.d {
width: 100px;
height: 100px;
background-color: #ff9900;
z-index: 1;
}
.h {
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.5;
display: none;
z-index: 0;
}
div {
position: absolute;
}
.d:hover + .h {
display: block;
}
Upvotes: 0
Reputation: 228
In addition to the previous answers: You could also add the "remove div" event listener to the "hov" element instead to the "div" element. That would solve your problem right away. Here's the whole code plus some minor hints/improvements:
var div = document.createElement("div");
div.className = "d";
document.body.appendChild(div);
var hov = document.createElement("div");
hov.className = "h";
var hover = false;
var overEvent = "mouseenter";
var overOut = "mouseleave";
div.addEventListener(overEvent, function(e) {
// if (hover) return; <-- you don't need that
document.body.appendChild(hov);
hover = !hover; // <-- that's easier to maintain incase you're changing the initial value
console.log("OVER");
});
hov.addEventListener(overOut, function(e) {
// if (!hover) return; <-- you don't need that
document.body.removeChild(hov);
hover = !hover;
console.log("OUT");
});
Hint: Your hov-element currently covers the whole screen, you'll have to put it to "100px" instead of "100%" for a better experience:
.h {
width: 100px;
height: 100px;
background-color: #000000;
opacity: 0.5;
z-index: 1;
}
Upvotes: 1
Reputation: 136
It happens because the upper element covers the element with handlers. Therefore, when the upper element occurs, the next mouse motion calls the handler for 'mouseleave'.
Upvotes: 0
Reputation: 3149
As Salasar already stated, this issue happens because the second div, the one that shows when hovering the first one, is showed exactly where the mouse is, and this triggers a mouse out event on the first div. What you can do to solve this issue, is configure your second div, the div.h, with 'pointer-events: none'. This will make it never to be a target of mouse events.
I have updated your example to show this working.
var div = document.createElement("div");
div.className = "d";
document.body.appendChild(div);
var hov = document.createElement("div");
hov.className = "h";
var hover = false;
var overEvent = "mouseenter";
var overOut = "mouseleave";
div.addEventListener(overEvent, function(e) {
if (hover) return;
document.body.appendChild(hov);
hover = true;
console.log("OVER");
});
div.addEventListener(overOut, function(e) {
if (!hover) return;
document.body.removeChild(hov);
hover = false;
console.log("OUT");
});
.d {
width: 100px;
height: 100px;
background-color: #ff9900;
z-index: 0;
}
.h {
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.5;
z-index: 1;
pointer-events: none;
}
div {
position: absolute;
}
Upvotes: 1