我onmouseout
在绝对定位的 div 中遇到问题。当鼠标点击 div 中的子元素时,mouseout 事件会触发,但我不希望它在鼠标离开父级绝对 div 之前触发。
如何防止mouseout
事件在没有 jquery 的情况下命中子元素时触发。
我知道这与事件冒泡有关,但我没有找到如何解决这个问题的运气。
我在这里找到了一个类似的帖子:如何禁用由子元素触发的 mouseout 事件?
然而,该解决方案使用 jQuery。
我onmouseout
在绝对定位的 div 中遇到问题。当鼠标点击 div 中的子元素时,mouseout 事件会触发,但我不希望它在鼠标离开父级绝对 div 之前触发。
如何防止mouseout
事件在没有 jquery 的情况下命中子元素时触发。
我知道这与事件冒泡有关,但我没有找到如何解决这个问题的运气。
我在这里找到了一个类似的帖子:如何禁用由子元素触发的 mouseout 事件?
然而,该解决方案使用 jQuery。
使用onmouseleave
.
或者,在 jQuery 中,使用mouseleave()
这正是您正在寻找的东西。例子:
<div class="outer" onmouseleave="yourFunction()">
<div class="inner">
</div>
</div>
或者,在 jQuery 中:
$(".outer").mouseleave(function(){
//your code here
});
一个例子是here。
对于在大多数情况下都可以使用的更简单的纯 CSS 解决方案pointer-events
,可以通过将 children 设置为none
.parent * {
pointer-events: none;
}
浏览器支持:IE11+
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,编辑更新的链接
而不是 onmouseout 使用 onmouseleave。
您没有向我们展示您的具体代码,因此我无法在您的具体示例中向您展示如何做到这一点。
但这很简单:只需将 onmouseout 替换为 onmouseleave 即可。
就是这样:)所以,简单:)
如果不确定如何操作,请参阅以下说明:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave_out
和平蛋糕:)享受它:)
这是基于以下内容的更优雅的解决方案。它解释了从多个级别的孩子冒泡的事件。它还解决了跨浏览器问题。
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);
如果您使用 jQuery,您还可以使用“mouseleave”函数,它会为您处理所有这些。
$('#thetargetdiv').mouseenter(do_something);
$('#thetargetdiv').mouseleave(do_something_else);
do_something 将在鼠标进入 targetdiv 或其任何子元素时触发,do_something_else 仅在鼠标离开 targetdiv 及其任何子元素时触发。
感谢 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
}
我认为Quirksmode有你需要的所有答案(不同的浏览器冒泡行为和mouseenter/mouseleave事件),但我认为事件冒泡混乱的最常见结论是使用像 JQuery 或 Mootools 这样的框架(它有mouseenter和mouseleave事件,这正是你直觉会发生的)。
看看他们是怎么做的,如果你愿意,你可以自己做,
或者你可以创建你的自定义“精益平均”版本的 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,但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="..."
在每一层上添加。
如果您可以访问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');
}
}
我们可以简单地检查 e.relatedTarget 是否有子类,如果为真则返回函数。
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;
}
}
});
我检查原始元素的偏移量以获取元素边界的页面坐标,然后确保仅在 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
事件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
就是生活,所以记住吧。
有一种简单的方法可以让它工作。您设置相同的类名的元素和所有孩子,然后:
element.onmouseover = function(event){
if (event.target.className == "name"){
/*code*/
}
}
对于 vanillajs,您也可以使用这种方式
document.querySelector('.product_items') && document.querySelector('.product_items').addEventListener('mouseleave', () => updateCart())
const updateCart = () => {
let total = 0;
document.querySelectorAll('input') && document.querySelectorAll('input').forEach(item => total += +item.value)
document.getElementById('total').innerHTML = total
}
<div class="product_items">
<div class="product_item">
<div class="product_name">
</div>
<div class="multiply__btn">
<button type="button">-</button>
<input name="test" type="text">
<button type="button">+</button>
</div>
</div>
<div class="product_item">
<div class="product_name">
</div>
<div class="multiply__btn">
<button type="button">-</button>
<input name="test" type="text">
<button type="button">+</button>
</div>
</div>
<div class="product_item">
<div class="product_name">
</div>
<div class="multiply__btn">
<button type="button">-</button>
<input name="test" type="text">
<button type="button">+</button>
</div>
</div>
</div>
<div id="total"></div>