当悬停父绝对div的子元素而没有jQuery时,防止onmouseout

2020/10/23 10:02 · javascript ·  · 0评论

onmouseout在绝对位置div中函数遇到麻烦当鼠标单击div中的一个子元素时,将触发mouseout事件,但是我不希望它触发,直到鼠标不在父级绝对div之外。

如何mouseout在没有jquery的情况阻止事件触发子事件时触发。

我知道这与事件冒泡有关,但是我没有运气找出如何解决这个问题。

我在这里找到了类似的帖子:如何禁用由子元素触发的mouseout事件?

但是,该解决方案使用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,请查看...

跨浏览器支持的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;
}

还有一个新的JSFiddleEDIT更新了链接

使用onmouseleave

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

这正是您要寻找的东西。例:

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

或者,在jQuery中:

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

一个例子在这里

对于在某些情况下(IE11或更高版本)可以使用的更简单的纯CSS解决方案可以通过将子级pointer-events设置为来删除子级none

.parent * {
     pointer-events: none;
}

这是一个基于以下内容的更优雅的解决方案。它说明了来自多个级别儿童的事件激增。它还解决了跨浏览器问题。

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);

而不是onmouseout使用onmouseleave。

您尚未向我们展示您的特定代码,因此我无法在您的特定示例中向您展示如何执行此操作。

但这很简单:只需将onmouseout替换为onmouseleave。

就是这样:)所以,很简单:)

如果不确定如何做,请参阅以下说明:

https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave_out

蛋糕的和平:)享受它:)

感谢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
    }

如果您使用的是jQuery,则还可以使用“ mouseleave”函数,该函数可以为您处理所有这些问题。

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

当鼠标进入targetdiv或其任何子级时,do_something将触发,仅当鼠标离开targetdiv及其任何子级时,do_something_else才会触发。

我认为Quirksmode具有所需的所有答案(不同的浏览器冒泡行为以及mouseenter / mouseleave事件),但我认为该事件冒泡最常见的结论使用JQuery或Mootools之类的框架(具有mouseentermouseleave事件,这正是您要直觉的事件)。

看看他们是如何做到这一点,如果你想,做你自己
你可以创建自定义只用事件部分(及其附属)Mootools的的“精益平均”版本。

尝试 mouseleave()

范例:

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

   </div>
</div>

;)

我找到了一个非常简单的解决方案,

只需使用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,
mouseentermouseleave是本机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="..."在每个图层上添加

如果您可以访问mouseout方法中事件附加到的元素,则可以使用contains()查看event.relatedTarget元素是否为子元素。

至于event.relatedTarget是哪个鼠标已经传递到,如果它不是一个子元素的元素,你的元素打探出。

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

在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-mouseenterng-mouseleave事件上遇到了一些困难

案例研究:

我创建了一个浮动导航菜单,当光标悬停在图标上时可以进行切换。

此菜单位于每个页面的顶部。

  • 要处理菜单上的显示/隐藏,我切换一个类。
    ng-class="{down: vm.isHover}"
  • 要切换vm.isHover,我使用ng鼠标事件。
    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事件上以及列表中的某个元素上时,将不再触发ng-mouse事件,并且我的浮动导航菜单也将不再关闭。

更进一步:

如您所料,此解决方案有效,但我不喜欢它。

我们不控制事件,这很糟糕。


另外,您必须具有访问
vm.isHover范围的权限才能实现此目的,并且它不可能或不可能,但会以某种或其他方式变脏。

如果有人想看,我可以摆弄。

但是,我没有其他解决方案了……

这是一个漫长的故事,我无法给您土豆,所以请原谅我的朋友。


无论如何,
pointer-events: none生命就是生命,所以要记住它。

只需检查e.relatedTarget是否具有子类,如果为true,则返回该函数。

    if ($(e.relatedTarget).hasClass("ctrl-btn")){
        return;
    }

这是为我工作的代码,我用于html5视频播放,暂停按钮切换悬停视频元素

element.on("mouseover mouseout", function(e) {

    if(e.type === "mouseout"){

        if ($(e.relatedTarget).hasClass("child-class")){
            return;
        }

    }

});
本文地址:http://javascript.askforanswer.com/dangxuantingfujueduidivdeziyuansuermeiyoujqueryshifangzhionmouseout.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!