当将鼠标hover在父绝对div的子元素上时,禁止使用jQuery

我在绝对positoned div中的onmouseout函数遇到问题。 当鼠标点击div中的子元素时,mouseout事件触发,但是我不希望它触发,直到鼠标离开父级绝对div。

我怎样才能防止mouseout事件触发一个没有jQuery的子元素。

我知道这与事件冒泡有关,但我找不到如何解决这个问题。

我在这里find了一个类似的post: 如何禁用子元素触发的鼠标事件?

不过,该解决scheme使用jQuery。

 function onMouseOut(event) { //this is the original element the event handler was assigned to var e = event.toElement || event.relatedTarget; if (e.parentNode == this || e == this) { return; } alert('MouseOut'); // handle mouse event here! } document.getElementById('parent').addEventListener('mouseout',onMouseOut,true); 

我做了一个快速JsFiddle演示,所有需要的CSS和HTML,检查出来…

编辑修复链接跨浏览器支持http://jsfiddle.net/RH3tA/9/

注意 ,这只检查直接父母,如果父div有嵌套的孩子,那么你必须以某种方式遍历元素父母寻找“原始元素”

编辑嵌套的孩子的例子

编辑修复希望跨浏览器

 function makeMouseOutFn(elem){ var list = traverseChildren(elem); return function onMouseOut(event) { var e = event.toElement || event.relatedTarget; if (!!~list.indexOf(e)) { return; } alert('MouseOut'); // handle mouse event here! }; } //using closure to cache all child elements var parent = document.getElementById("parent"); parent.addEventListener('mouseout',makeMouseOutFn(parent),true); //quick and dirty DFS children traversal, function traverseChildren(elem){ var children = []; var q = []; q.push(elem); while (q.length > 0) { var elem = q.pop(); children.push(elem); pushAll(elem.children); } function pushAll(elemArray){ for(var i=0; i < elemArray.length; i++) { q.push(elemArray[i]); } } return children; } 

而一个新的JSFiddle编辑更新链接

对于一些更简单的纯CSS解决scheme ( IE11或更新版本 ),可以通过将其设置为none

 .parent * { pointer-events: none; } 

使用onmouseleave

或者,在jQuery中,使用mouseleave()

这是你正在寻找的确切的东西。 例:

 <div class="outer" onmouseleave="yourFunction()"> <div class="inner"> </div> </div> 

或者,在jQuery中:

 $(".outer").mouseleave(function(){ //your code here }); 

这里就是一个例子。

下面是一个更优雅的解决scheme。 它说明了来自不止一个级别的孩子的事件冒泡。 它也解决了跨浏览器问题。

 function onMouseOut(this, event) { //this is the original element the event handler was assigned to var e = event.toElement || event.relatedTarget; //check for all children levels (checking from bottom up) while(e && e.parentNode && e.parentNode != window) { if (e.parentNode == this|| e == this) { if(e.preventDefault) e.preventDefault(); return false; } e = e.parentNode; } //Do something u need here } document.getElementById('parent').addEventListener('mouseout',onMouseOut,true); 

感谢Amjad Masad激发了我的灵感。

我有以下的解决scheme,似乎在IE9,FF和Chrome的工作,代码是很短(没有复杂的封闭和横向的孩子的东西):

  DIV.onmouseout=function(e){ // check and loop relatedTarget.parentNode // ignore event triggered mouse overing any child element or leaving itself var obj=e.relatedTarget; while(obj!=null){ if(obj==this){ return; } obj=obj.parentNode; } // now perform the actual action you want to do only when mouse is leaving the DIV } 

如果你使用的是jQuery,你也可以使用“mouseleave”函数,它为你处理所有这些。

 $('#thetargetdiv').mouseenter(do_something); $('#thetargetdiv').mouseleave(do_something_else); 

do_something会在鼠标进入targetget或其任何子节点时触发,do_something_else只会在鼠标离开targettarv及其任何子节点时触发。

我认为Quirksmode有你需要的所有答案(不同的浏览器冒泡行为和mouseenter / mouseleave事件),但我认为这个事件冒泡混乱的最常见的结论使用像JQuery或Mootools(它有鼠标mouseleave事件,这正是你直觉会发生)。

看看他们是怎么做的,如果你愿意的话,自己动手吧
或者你可以用事件部分(及其依赖关系) 创build自定义的 “精益平均”版本的Mootools。

试试mouseleave()

例如:

 <div id="parent" mouseleave="function"> <div id="child"> </div> </div> 

;)

我find了一个非常简单的解决scheme,

只是使用onmouseleave =“myfunc()”事件比onmousout =“myfunc()”事件

在我的代码中,它的工作!

例:

 <html> <head> <script type="text/javascript"> function myFunc(){ document.getElementById('hide_div').style.display = 'none'; } function ShowFunc(){ document.getElementById('hide_div').style.display = 'block'; } </script> </head> <body> <div onmouseleave="myFunc()" style='border:double;width:50%;height:50%;position:absolute;top:25%;left:25%;'> Hover mouse here <div id='child_div' style='border:solid;width:25%;height:25%;position:absolute;top:10%;left:10%;'> CHILD <br/> It doesn't fires if you hover mouse over this child_div </div> </div> <div id="hide_div" >TEXT</div> <a href='#' onclick="ShowFunc()">Show "TEXT"</a> </body> </html> 

相同的例子与鼠标function:

 <html> <head> <script type="text/javascript"> function myFunc(){ document.getElementById('hide_div').style.display = 'none'; } function ShowFunc(){ document.getElementById('hide_div').style.display = 'block'; } </script> </head> <body> <div onmouseout="myFunc()" style='border:double;width:50%;height:50%;position:absolute;top:25%;left:25%;'> Hover mouse here <div id='child_div' style='border:solid;width:25%;height:25%;position:absolute;top:10%;left:10%;'> CHILD <br/> It fires if you hover mouse over this child_div </div> </div> <div id="hide_div">TEXT</div> <a href='#' onclick="ShowFunc()">Show "TEXT"</a> </body> </html> 

希望能帮助到你 :)

有两种方法来处理这个问题。

1)检查你的callbackevent.target结果,看看它是否符合你的父div

 var g_ParentDiv; function OnMouseOut(event) { if (event.target != g_ParentDiv) { return; } // handle mouse event here! }; window.onload = function() { g_ParentDiv = document.getElementById("parentdiv"); g_ParentDiv.onmouseout = OnMouseOut; }; <div id="parentdiv"> <img src="childimage.jpg" id="childimg" /> </div> 

2)或者在callback函数中使用事件捕获和调用event.stopPropagation

 var g_ParentDiv; function OnMouseOut(event) { event.stopPropagation(); // don't let the event recurse into children // handle mouse event here! }; window.onload = function() { g_ParentDiv = document.getElementById("parentdiv"); g_ParentDiv.addEventListener("mouseout", OnMouseOut, true); // pass true to enable event capturing so parent gets event callback before children }; <div id="parentdiv"> <img src="childimage.jpg" id="childimg" /> </div> 

我使它像这样的魅力工作:

 function HideLayer(theEvent){ var MyDiv=document.getElementById('MyDiv'); if(MyDiv==(!theEvent?window.event:theEvent.target)){ MyDiv.style.display='none'; } } 

啊, MyDiv标签是这样的:

 <div id="MyDiv" onmouseout="JavaScript: HideLayer(event);"> <!-- Here whatever divs, inputs, links, images, anything you want... --> <div> 

这样,当onmouseout进入一个孩子, style.display='none'等… style.display='none'不执行; 但是当鼠标移出MyDiv时,它会运行。

所以不需要停止传播,使用定时器等

谢谢你的例子,我可以从他们这个代码。

希望这有助于某人。

也可以这样改进:

 function HideLayer(theLayer,theEvent){ if(theLayer==(!theEvent?window.event:theEvent.target)){ theLayer.style.display='none'; } } 

然后DIVs标签是这样的:

 <div onmouseout="JavaScript: HideLayer(this,event);"> <!-- Here whatever divs, inputs, links, images, anything you want... --> <div> 

所以更通用的,不仅是一个div,也不需要在每一层添加id="..."

我检查原始元素的偏移量以获取元素边界的页面坐标,然后确保只有当mouseout超出边界时才会触发mouseout操作。 肮脏,但它的作品。

 $(el).live('mouseout', function(event){ while(checkPosition(this, event)){ console.log("mouseovering including children") } console.log("moused out of the whole") }) var checkPosition = function(el, event){ var position = $(el).offset() var height = $(el).height() var width = $(el).width() if (event.pageY > position.top || event.pageY < (position.top + height) || event.pageX > position.left || event.pageX < (position.left + width)){ return true } } 
 var elem = $('#some-id'); elem.mouseover(function () { // Some code here }).mouseout(function (event) { var e = event.toElement || event.relatedTarget; if (elem.has(e).length > 0) return; // Some code here }); 

如果你添加(或有)CSS类或id到父元素,那么你可以做这样的事情:

 <div id="parent"> <div> </div> </div> JavaScript: document.getElementById("parent").onmouseout = function(e) { e = e ? e : window.event //For IE if(e.target.id == "parent") { //Do your stuff } } 

所以东西只有在事件在父div上时才会被执行。

我只是想和你分享一些东西。
ng-mouseenterng-mouseleave事件让我感到困难。

案例研究:

我创build了一个浮动导航菜单,当光标位于图标上方时,该菜单将被切换。
该菜单位于每页的顶部。

  • 为了处理菜单上的显示/隐藏,我切换了一个类。
    ng-class="{down: vm.isHover}"
  • 要切换vm.isHover ,我使用ng鼠标事件。
    ng-mouseenter="vm.isHover = true"
    ng-mouseleave="vm.isHover = false"

现在,一切都很好,按预期工作。
解决scheme干净简单。

即将到来的问题:

具体来看,我有一个元素列表。
当光标位于列表的某个元素上时,我添加了一个操作面板。
我使用了与上面相同的代码来处理行为。

问题:

我想出了当我的光标在浮动导航菜单上,也是在一个元素的顶部,彼此之间有冲突。
行动面板出现,浮动导航隐藏。

问题是,即使光标位于浮动导航菜单上,列表元素ng-mouseenter也会被触发。
这对我来说没有意义,因为我期望鼠标传播事件的自动中断。
我必须说,我感到失望,我花了一些时间来找出这个问题。

第一个想法:

我试图使用这些:

  • $event.stopPropagation()
  • $event.stopImmediatePropagation()

我结合了很多ng指针事件(mousemove,mouveover,…),但没有任何帮助。

CSS解决scheme:

我发现了一个简单的CSS属性,我越来越多地使用的解决scheme:

 pointer-events: none; 

基本上,我是这样使用它(在我的列表元素上):

 ng-style="{'pointer-events': vm.isHover ? 'none' : ''}" 

有了这个棘手的问题,ng-mouse事件将不再被触发,当光标位于其上方并且位于列表中的某个元素上时,我的浮动导航菜单将不再自动closures。

进一步:

正如你所期望的,这个解决scheme的工作原理,但我不喜欢它。
我们不控制我们的事件,这是不好的。
此外,您必须有权访问vm.isHover范围才能实现这一目标,这可能不可能或不可能,但以某种方式肮脏。
如果有人想看,我可以做一个小提琴。

不过,我没有另一个解决scheme…
这是一个很长的故事,我不能给你一个土豆,所以请原谅我的朋友。
无论如何, pointer-events: none是生活,所以记住它。

如果您有权访问mouseout方法内部附加的元素,则可以使用contains()来查看event.relatedTarget是否为子元素。

由于event.relatedTarget是鼠标已经进入的元素,如果它不是子元素,你已经被挖出元素。

 div.onmouseout = function (event) { if (!div.contains(event.relatedTarget)) { // moused out of div } }