问题
In a library I am using I have the task of moving an element to the front of the dom when it is hovered over. (I make it bigger so I need to see it, then shrink it back when mouse out).
The library I am using has neat solution which uses appendChildren on the active element to move it to the end its parent so further towards the end of the dom and in turn on top.
The problem is I believe that because the element you are moving is the one you are hovering over the mouseout event is lost. Your mouse is still over the node but the mouseout event isn't being fired.
I have stripped the functionality down to confirm the issue. It works fine in firefox but not in any version of IE. I'm using jquery here for speed. Solutions can be in plain old javascript..which would be a preference as it might need to go back up stream.
I can't use z-index here as the elements are vml, the library is Raphael and I am using the toFront call. Sample using ul/li to show issue in a simple example
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="js/jquery.min.js" type="text/javascript"></script>
<style>
li
{
border:1px solid black;
}
</style>
</head>
<body>
<ul><li>Test 1</li></ul>
<ul><li>Test 2</li></ul>
<ul><li>Test 3</li></ul>
<ul><li>Test 4</li></ul>
<script>
$(function(){
$("li").mouseover(function(){
$(this).css("border-color","red");
this.parentNode.appendChild(this);
});
$("li").mouseout(function(){
$(this).css("border-color","black");
});
});
</script>
</body>
</html>
Edit: Here is a link to a js paste bin to see it in action. http://jsbin.com/obesa4
**Edit 2: ** See all comments on all answers before posting as lots more info in that.
回答1:
The problem is that IE handles mouseover
differently, because it behaves like mouseenter
and mousemove
combined on an element. In other browsers it's just mouseenter
.
So even after your mouse has entered the target element and you've changed it's look and reappended it to it's parent mouseover
will still fire for every movement of the mouse, the element gets reappended again, which prevents other event handlers from being called.
The solution is to emulate the correct mouseover
behavior so that actions in onmouseover
are executed only once.
$("li").mouseover( function() {
// make sure these actions are executed only once
if ( this.style.borderColor != "red" ) {
this.style.borderColor = "red";
this.parentNode.appendChild(this);
}
});
Examples
- Extented demo of yours
- Example demonstrating the
mouseover
difference between browsers (bonus: native javascript)
回答2:
I was able to get it working with nested divs and a mouseenter event on the parent:
<div id="frame">
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
</div>
...
$('#frame').mouseenter(function() {
$(".box").css("border-color", "black");
});
Here's a working version using Raphael:
http://jsfiddle.net/xDREx/
回答3:
I modified @galambalazs' answer because I found that it failed if I hovered really quickly over the li elements, as some of the elements would still retain the mouseover
effect.
I came up with a solution that removes the hover state on elements that failed to trigger the mouseover
event by pushing these elements to a stack whenever the mouseover
even is triggered. Anytime either the mouseover
or mouseout
event is called, I pop the elements from this array and remove the styles placed on it:
$(function(){
// Track any hovered elements
window.hovered = [];
$("li").mouseover(function() {
// make sure that these actions happen only once
if ( $(this).css("border-color") != "red" ) {
resetHovered (); // Reset any previous hovered elements
$(this).css("border-color","red");
this.parentNode.appendChild(this);
hovered.push(this);
}
});
$("li").mouseout(function(){
resetHovered(); // Reset any previous hovered elements
});
// Reset any elements on the stack
function resetHovered () {
while ( hovered.length > 0 ) {
var elem = hovered.pop();
$(elem).css("border-color","black");
}
}
});
I've tested this solution with IE 11. A functional example can be found here.
回答4:
That's wonky, and seems to be IE-only (but so is VML). If the parent element has a height specified, you can attach the mouseout handler to the parent... but it sounds like that won't work in your situation. Your best alternative is to use mouseover on adjacent elements to hide it:
$(function()
{
$("li").mouseover(function()
{
$("li").css("border-color", "black");
$(this).css("border-color", "red");
this.parentNode.appendChild(this);
});
});
Or SVG. You can use z-index in SVG.
来源:https://stackoverflow.com/questions/3686132/move-active-element-loses-mouseout-event-in-internet-explorer