我onmouseout
在绝对位置div中的函数遇到麻烦。当鼠标单击div中的一个子元素时,将触发mouseout事件,但我不希望它触发,直到鼠标不在父绝对div之外。
我如何防止mouseout
事件在没有jquery的情况下击中子元素而触发。
我知道这与事件冒泡有关,但是我没有运气去寻找如何解决这个问题的方法。
我在这里找到了类似的帖子:如何禁用由子元素触发的mouseout事件?
但是,该解决方案使用jQuery。
我onmouseout
在绝对位置div中的函数遇到麻烦。当鼠标单击div中的一个子元素时,将触发mouseout事件,但我不希望它触发,直到鼠标不在父绝对div之外。
我如何防止mouseout
事件在没有jquery的情况下击中子元素而触发。
我知道这与事件冒泡有关,但是我没有运气去寻找如何解决这个问题的方法。
我在这里找到了类似的帖子:如何禁用由子元素触发的mouseout事件?
但是,该解决方案使用jQuery。
Answers:
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,请查看...
跨浏览器支持的EDIT FIXED链接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,EDIT更新了链接
mouseleave
是正确的答案
使用onmouseleave
。
或者,在jQuery中,使用 mouseleave()
这正是您要寻找的东西。例:
<div class="outer" onmouseleave="yourFunction()">
<div class="inner">
</div>
</div>
或者,在jQuery中:
$(".outer").mouseleave(function(){
//your code here
});
一个例子在这里。
onMouseLeave
我最终也使用了它,因为它不会冒泡。
mouseleave
不能取消。
对于在某些情况下(IE11或更高版本)可以使用的更简单的纯CSS解决方案,可以通过将子级pointer-events
设置为来删除子级none
.parent * {
pointer-events: none;
}
pointer-events
属性
这是一个基于以下内容的更优雅的解决方案。它说明了来自多个级别儿童的事件激增。它还解决了跨浏览器的问题。
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);
this
但从功能定义行中删除了@GregoryLewis提到的已解决问题。同样,为了获得更多的跨浏览器支持,请尝试以下操作:if(window.addEventListener){document.getElementById('parent')。addEventListener('mouseout',onMouseOut,true); }否则,如果(window.attachEvent){document.getElementById('parent')。attachEvent(“ onmouseout”,onMouseOut); }
感谢Amjad Masad启发了我。
我有以下解决方案似乎可以在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
}
而不是onmouseout使用onmouseleave。
您尚未向我们展示您的特定代码,因此我无法在您的特定示例中向您展示如何执行此操作。
但这很简单:只需将onmouseout替换为onmouseleave。
就是这样:)所以,简单:)
如果不确定如何做,请参阅以下说明:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave_out
蛋糕的和平:)享受它:)
我认为Quirksmode具有所需的所有答案(不同的浏览器冒泡行为以及mouseenter / mouseleave事件),但是我认为该事件冒泡最常见的结论是使用JQuery或Mootools之类的框架(具有mouseenter和mouseleave事件,这正是您要直觉的事件)。
看看他们是如何做到这一点,如果你想,做你自己
或你可以创建自定义只用事件部分(及其附属)Mootools的的“精益平均”版本。
我找到了一个非常简单的解决方案,
只需使用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>
具有mouseout功能的相同示例:
<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>
希望能帮助到你 :)
尽管您提到的解决方案使用jquery, mouseenter和mouseleave是本机dom事件,所以您可以在没有jquery的情况下使用。
有两种方法可以解决此问题。
1)检查您的回调中的event.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)或使用事件捕获并在回调函数中调用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'
不会执行;但是当onmouseout从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="..."
在每个图层上添加。
在Angular 5、6和7上
<div (mouseout)="onMouseOut($event)"
(mouseenter)="onMouseEnter($event)"></div>
然后
import {Component,Renderer2} from '@angular/core';
...
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit, OnDestroy {
...
public targetElement: HTMLElement;
constructor(private _renderer: Renderer2) {
}
ngOnInit(): void {
}
ngOnDestroy(): void {
//Maybe reset the targetElement
}
public onMouseEnter(event): void {
this.targetElement = event.target || event.srcElement;
console.log('Mouse Enter', this.targetElement);
}
public onMouseOut(event): void {
const elementRelated = event.toElement || event.relatedTarget;
if (this.targetElement.contains(elementRelated)) {
return;
}
console.log('Mouse Out');
}
}
我检查原始元素的偏移量以获得元素边界的页面坐标,然后确保仅当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-mouseenter
和and ng-mouseleave
事件有些困难。
案例研究:
我创建了一个浮动导航菜单,当光标悬停在图标上时可以切换。
该菜单位于每个页面的顶部。
ng-class="{down: vm.isHover}"
ng-mouseenter="vm.isHover = true"
ng-mouseleave="vm.isHover = false"
目前,一切都很好,并按预期工作。
该解决方案既干净又简单。
传入的问题:
在特定视图中,我有一个元素列表。
当光标位于列表的元素上方时,我添加了一个操作面板。
我使用与上面相同的代码来处理此行为。
问题:
我想出了当光标位于浮动导航菜单上以及元素顶部时,彼此之间存在冲突。
动作面板出现,浮动导航被隐藏。
事实是,即使光标位于浮动导航菜单上,也会触发列表元素ng-mouseenter。
这对我来说毫无意义,因为我期望鼠标传播事件会自动中断。
我必须说,我很失望,我花了一些时间来找出问题所在。
首先的想法:
我试图使用这些:
$event.stopPropagation()
$event.stopImmediatePropagation()
我结合了很多ng指针事件(mousemove,mouveover,...),但是没有一个帮助我。
CSS解决方案:
我找到了一个使用越来越多的简单CSS属性的解决方案:
pointer-events: none;
基本上,我这样使用它(在我的列表元素上):
ng-style="{'pointer-events': vm.isHover ? 'none' : ''}"
使用这个棘手的控件,将不再触发ng-mouse事件,并且当光标悬停在其上方以及列表中的某个元素上方时,我的浮动导航菜单也将不再关闭。
更进一步:
如您所料,此解决方案有效,但我不喜欢它。
我们不控制事件,这很糟糕。
另外,您必须具有访问vm.isHover
范围的权限才能实现此目的,并且它不可能或不可能,但在某种程度上是肮脏的。
如果有人想看,我可以摆弄。
但是,我没有其他解决方案了……
这是一个漫长的故事,我无法给您土豆,所以请原谅我的朋友。
无论如何,pointer-events: none
生命就是生命,所以要记住它。