如何使用绝对定位的非后代实现 mouseleave 效果?
How to achieve mouseleave effect with absolutely-positioned non-descendants?
标准 mouseout
事件的一个问题是,它不仅会在光标离开元素外部边界所界定的屏幕区域时触发,还会在光标悬停在其中包含的其他元素上时触发这个周长。
jQuery 的 mouseleave
事件的基本原理是 仅在 光标离开由元素的外部边界界定的区域时发出信号.
不幸的是,这似乎只有在 "obstructing" 元素是 "obstructed" 元素的后代时才有效。如果 "obstructing" 元素通过绝对定位位于它所在的位置,则当鼠标悬停在其上时,将触发 "obstructed" 元素上的 mouseleave
事件。
例如,使用以下 HTML:
<div id="b-div">
<div id="d-div"><span>d</span></div>
</div>
<div id="c-div"><span>c</span></div>
...#d-div
是 #b-div
的真正后代,而 #c-div
不是,但是,但是我们可以对其进行样式设置,使其 "obstructs" #b-div
都一样。 this jsFiddle.
对此进行了说明
如果现在在 #b-div
上定义以下事件:
$( '#b-div' ).bind( {
mouseenter: function () {
$( this ).addClass( 'outlined' );
},
mouseleave: function () {
$( this ).removeClass( 'outlined' );
}
} );
...然后将鼠标悬停在 #b-div
的外围会导致该外围出现蓝色轮廓,除非 鼠标悬停在 #c-div
.
有没有办法用 #b-div
和 #c-div
获得与 mouseleave
用 #b-div
和 #d-div
达到相同的效果?
编辑:我已经修复了 jsFiddle 中显示的示例。此示例的原始版本显示了不具代表性的特殊情况,其中所有障碍元素都与障碍元素重叠。在这种特殊情况下,可以通过在阻塞元素和被阻塞元素上定义相同的事件来 模拟 所需的效果,从而实际上将阻塞元素变成被阻塞元素的一个补丁元素。当阻碍元素没有完全包含在被阻碍元素的外围时,这将不起作用(如修改后的 jsFiddle 所示)。更一般地说,任何基于在阻碍元素上使用 mouseover
事件的解决方案都注定会失败,因为 真实 问题是为了防止(或使无效)虚假mouseleave
在被阻挡的元素上。
这样做是基于您最初的 post,其中 #c-div
完全包含在 #b-div
中:
$('#b-div, #c-div').on( {
mouseenter: function (ev) {
$('#b-div').addClass('outlined');
},
mouseleave: function (ev) {
$('#b-div').removeClass('outlined');
}
});
由于 #c-div
可能并不总是完全包含在 #b-div
中,如果您添加此样式,则可以使用现有代码:
#c-div {
pointer-events: none;
}
但这将无法使用鼠标与 #c-div
交互。
如果您 需要与 #c-div
、 和 进行交互,则它不完全在 #b-div
内,您可以像这样使用 Element.getBoundingClientRect:
$('#b-div, #c-div').on('mousemove mouseleave',
function(ev) {
var br= $('#b-div')[0].getBoundingClientRect();
$('#b-div').toggleClass(
'outlined',
ev.pageX > br.left && ev.pageX < br.left+br.width &&
ev.pageY > br.top && ev.pageY < br.top +br.height
)
}
);
如果您无法使用 Rich 的 pointer-events: none
建议(也许您需要 support IE 10 or you do need to interact with the absolutely positioned div), you can manually check that the event is not going to #c-div
using relatedTarget
。
但是,您还必须检查 #c-div
的 mouseleave 不会转到 #b-div
。
$( '#b-div' ).bind( {
mouseenter: function () {
$( this ).addClass( 'outlined' );
},
mouseleave: function (e) {
if (e.relatedTarget.id == 'c-div' || $.contains(document.getElementById('c-div'), e.relatedTarget)) {
return;
}
$( this ).removeClass( 'outlined' );
}
} );
$( '#c-div' ).bind( {
mouseleave: function (e) {
if (e.relatedTarget.id == 'b-div' || $.contains(document.getElementById('b-div'), e.relatedTarget)) {
return;
}
$( '#b-div' ).removeClass( 'outlined' );
}
});
#a-div {
position: relative;
margin: 20px;
}
#b-div {
height: 100px;
width: 100px;
background-color: #555;
padding: 50px;
}
#c-div {
position: absolute;
height: 50px;
width: 200px;
top: 100px;
left: 100px;
background-color: #999;
}
#d-div {
height: 50px;
width: 50px;
background-color: #ddd;
text-align: center;
}
#c-div span {
margin: 21.5px;
line-height: 50px;
}
#d-div span {
margin: auto;
line-height: 50px;
}
.outlined {
outline: 10px solid steelblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a-div">
<div id="b-div"><div id="d-div"><span>d</span></div></div>
<div id="c-div"><span>c</span></div>
</div>
标准 mouseout
事件的一个问题是,它不仅会在光标离开元素外部边界所界定的屏幕区域时触发,还会在光标悬停在其中包含的其他元素上时触发这个周长。
jQuery 的 mouseleave
事件的基本原理是 仅在 光标离开由元素的外部边界界定的区域时发出信号.
不幸的是,这似乎只有在 "obstructing" 元素是 "obstructed" 元素的后代时才有效。如果 "obstructing" 元素通过绝对定位位于它所在的位置,则当鼠标悬停在其上时,将触发 "obstructed" 元素上的 mouseleave
事件。
例如,使用以下 HTML:
<div id="b-div">
<div id="d-div"><span>d</span></div>
</div>
<div id="c-div"><span>c</span></div>
...#d-div
是 #b-div
的真正后代,而 #c-div
不是,但是,但是我们可以对其进行样式设置,使其 "obstructs" #b-div
都一样。 this jsFiddle.
如果现在在 #b-div
上定义以下事件:
$( '#b-div' ).bind( {
mouseenter: function () {
$( this ).addClass( 'outlined' );
},
mouseleave: function () {
$( this ).removeClass( 'outlined' );
}
} );
...然后将鼠标悬停在 #b-div
的外围会导致该外围出现蓝色轮廓,除非 鼠标悬停在 #c-div
.
有没有办法用 #b-div
和 #c-div
获得与 mouseleave
用 #b-div
和 #d-div
达到相同的效果?
编辑:我已经修复了 jsFiddle 中显示的示例。此示例的原始版本显示了不具代表性的特殊情况,其中所有障碍元素都与障碍元素重叠。在这种特殊情况下,可以通过在阻塞元素和被阻塞元素上定义相同的事件来 模拟 所需的效果,从而实际上将阻塞元素变成被阻塞元素的一个补丁元素。当阻碍元素没有完全包含在被阻碍元素的外围时,这将不起作用(如修改后的 jsFiddle 所示)。更一般地说,任何基于在阻碍元素上使用 mouseover
事件的解决方案都注定会失败,因为 真实 问题是为了防止(或使无效)虚假mouseleave
在被阻挡的元素上。
这样做是基于您最初的 post,其中 #c-div
完全包含在 #b-div
中:
$('#b-div, #c-div').on( {
mouseenter: function (ev) {
$('#b-div').addClass('outlined');
},
mouseleave: function (ev) {
$('#b-div').removeClass('outlined');
}
});
由于
#c-div
可能并不总是完全包含在 #b-div
中,如果您添加此样式,则可以使用现有代码:
#c-div {
pointer-events: none;
}
但这将无法使用鼠标与 #c-div
交互。
如果您 需要与 #c-div
、 和 进行交互,则它不完全在 #b-div
内,您可以像这样使用 Element.getBoundingClientRect:
$('#b-div, #c-div').on('mousemove mouseleave',
function(ev) {
var br= $('#b-div')[0].getBoundingClientRect();
$('#b-div').toggleClass(
'outlined',
ev.pageX > br.left && ev.pageX < br.left+br.width &&
ev.pageY > br.top && ev.pageY < br.top +br.height
)
}
);
如果您无法使用 Rich 的 pointer-events: none
建议(也许您需要 support IE 10 or you do need to interact with the absolutely positioned div), you can manually check that the event is not going to #c-div
using relatedTarget
。
但是,您还必须检查 #c-div
的 mouseleave 不会转到 #b-div
。
$( '#b-div' ).bind( {
mouseenter: function () {
$( this ).addClass( 'outlined' );
},
mouseleave: function (e) {
if (e.relatedTarget.id == 'c-div' || $.contains(document.getElementById('c-div'), e.relatedTarget)) {
return;
}
$( this ).removeClass( 'outlined' );
}
} );
$( '#c-div' ).bind( {
mouseleave: function (e) {
if (e.relatedTarget.id == 'b-div' || $.contains(document.getElementById('b-div'), e.relatedTarget)) {
return;
}
$( '#b-div' ).removeClass( 'outlined' );
}
});
#a-div {
position: relative;
margin: 20px;
}
#b-div {
height: 100px;
width: 100px;
background-color: #555;
padding: 50px;
}
#c-div {
position: absolute;
height: 50px;
width: 200px;
top: 100px;
left: 100px;
background-color: #999;
}
#d-div {
height: 50px;
width: 50px;
background-color: #ddd;
text-align: center;
}
#c-div span {
margin: 21.5px;
line-height: 50px;
}
#d-div span {
margin: auto;
line-height: 50px;
}
.outlined {
outline: 10px solid steelblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a-div">
<div id="b-div"><div id="d-div"><span>d</span></div></div>
<div id="c-div"><span>c</span></div>
</div>