我有一个绝对定位的div,我试图跟踪鼠标何时移动到它上面,以及当鼠标离开时。不幸的是,单击框中的文本偶尔会触发mouseleave事件。
DEMO:js fiddle
我该如何防止这种情况?
JS
let tooltip = document.createElement('div');
tooltip.innerHTML = 'HELLO WORLD';
tooltip.setAttribute('class', 'tooltip');
tooltip.style.display = 'none';
tooltip.onclick = evt => {
console.log('click')
evt.stopPropagation();
}
tooltip.ondblclick = evt => {
console.log('double click')
evt.stopPropagation();
}
tooltip.onmouseenter = () => {
console.log('tooltip mouse OVER');
}
tooltip.onmouseleave = () => {
console.log('tooltip mouse OUT')
}
tooltip.style.left = '290px';
tooltip.style.top = '50px';
tooltip.style.display = 'block';
document.body.appendChild(tooltip);
HTML
<div style="width: 300px; height: 300px; background-color: lightblue">
</div>
CSS
.tooltip {
position: absolute;
/*display: none;*/
left: 100;
top: 100;
min-width: 80px;
height: auto;
background: none repeat scroll 0 0 #ffffff;
border: 1px solid #6F257F;
padding: 14px;
text-align: center;
}
答案 0 :(得分:11)
我之前看过这里的答案和评论,但最近找到了一种检查mouseleave
事件是否被错误触发的方法
我在mouseleave
处理程序中添加了一个检查:
private handleMouseLeave(event: MouseEvent) {
if(event.relatedTarget || event.toElement){
// do whatever
}
// otherwise ignore
}
根据我在Chrome v64上的测试,只要快速点击导致null
事件被触发,这两个值都将为mouseleave
。 relatedTarget
用于较旧的浏览器兼容性
注意:如果鼠标离开null
元素并进入浏览器(例如标签,菜单等)或离开浏览器窗口,这两个值也将为target
。对于我的目的,这不是一个问题,因为它是我正在使用的滑动菜单,并且离开浏览器窗口不应该在我的特定情况下关闭菜单。
注意:最新的Firefox版本(2018年2月)似乎每次点击我的菜单都会触发mouseleave
!将不得不研究它
答案 1 :(得分:10)
这似乎是一个错误(我可以在Chrome中重现它,点击鼠标按下并且鼠标在彼此之后快速发生)。
我建议通过检查事件被触发时鼠标是否仍在元素上来解决此问题:
tooltip.onmouseleave = (e) => {
if (tooltip === document.elementFromPoint(e.clientX, e.clientY)) {
console.log('false positive');
return;
}
console.log('tooltip mouse OUT')
}
缺点是当浏览器窗口失去焦点时,这也被认为是误报。如果这对您来说是个问题,请检查this answer。
答案 2 :(得分:4)
我也碰到了这个bug。在我的例子中,我将标签包装的复选框添加到列表中,并将列表包装在div中。我还使用了一些<hr>
标签的列表项。如果您快速单击复选框和标签,则偶尔会在包装div上触发mouseleave
事件。这不应该发生,因为所有点击的元素都是div.wrapper
的子元素。
...
wrapper.addEventListener(
'mouseleave',
(e) => {
logger('mouseleave fired');
console.log('mouseleave fired', e);
},
false
);
...
这是复制品的GIF。单击线索区域(授予一些强度和移动),单击标签中的事件和输入框正在触发,然后您看到两个 mouseleave 事件触发错误,然后第三个鼠标真正触发离开了蓝色区域。
答案 3 :(得分:0)
@trincot的回答几乎对我有用。就我而言,我正在处理弹出窗口。当我单击一个按钮时,它会触发一个弹出窗口,该弹出窗口显示在触发按钮的顶部。因此document.elementFromPoint(e.clientX, e.clientY)
返回popover元素而不是触发按钮。这是我解决此问题的方法:
mouseleave(ev: MouseEvent) {
const trigger: HTMLElement = document.getElementById('#myTrigger');
const triggerRect = trigger.getBoundingClientRect();
const falsePositive = isWithingARect(ev.clientX, ev.clientY, triggerRect);
if (!falsePositive) {
// do what needs to be done
}
}
function isWithingARect(x: number, y: number, rect: ClientRect) {
const xIsWithin = x > rect.left && x < rect.right;
const yIsWithin = y > rect.top && y < rect.bottom;
return xIsWithin && yIsWithin;
}
答案 4 :(得分:0)
使用MouseEvent.buttons检查是否按下了主按钮。
tooltip.onmouseleave = (e) => {
if (e.buttons !== 1) {
console.log('tooltip mouse OUT')
}
}
答案 5 :(得分:-1)
var trackmouseup = null;
$('.box').mouseup(function(event){
if(trackmouseup){
clearTimeout(trackmouseup);
}
trackmouseup = setTimeout(function(){
trackmouseup = null;
}, 2); //it must be 2ms or more
});
$('.box').mouseleave(function(event){
//if this event is triggered by click, there must be a mouse up event triggered 2ms ago
if(trackmouseup){
return;
}
//to do something
});