Mouseleave triggered by click
我有一个绝对定位的div,我试图跟踪鼠标何时在其上移动以及鼠标何时离开。 不幸的是,偶尔单击框中的文本会触发mouseleave事件。
演示:js小提琴
我该如何预防?
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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
1 |
的CSS
1 2 3 4 5 6 7 8 9 10 11 12 | .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; } |
我以前曾在这里查看过答案和评论,但是最近找到了一种检查
我在
1 2 3 4 5 6 | private handleMouseLeave(event: MouseEvent) { if(event.relatedTarget || event.toElement){ // do whatever } // otherwise ignore } |
根据我在Chrome v64上的测试,每当快速单击导致触发
注意:如果鼠标离开
注意:最新的Firefox版本(2018年2月)似乎在我的菜单上单击每次都会触发
这似乎是一个错误(我可以在Chrome中通过单击使鼠标按下和鼠标向上快速发生的点击来复制它)。
我建议通过检查事件触发时鼠标是否仍在元素上来解决此问题:
1 2 3 4 5 6 7 | tooltip.onmouseleave = (e) => { if (tooltip === document.elementFromPoint(e.clientX, e.clientY)) { console.log('false positive'); return; } console.log('tooltip mouse OUT') } |
缺点是,当浏览器窗口失去焦点时,这也被认为是误报。如果这是您的问题,请检查此答案。
我也遇到了这个错误。就我而言,我将标签包装的复选框添加到列表中,并将列表包装在div中。我还使用了一些
1 2 3 4 5 6 7 8 9 10 | ... wrapper.addEventListener( 'mouseleave', (e) => { logger('mouseleave fired'); console.log('mouseleave fired', e); }, false ); ... |
jsfiddle演示
这是复制品的gif图像。在提示区域内单击(允许一定的强度和移动),单击标签中的事件,并触发输入框,然后您看到两个错误触发的mouseleave事件,然后在鼠标真正离开蓝色区域时看到第三个事件。
@trincot的回答几乎对我有用。就我而言,我正在处理弹出窗口。当我单击一个按钮时,它会触发一个弹出窗口,该弹出窗口显示在触发按钮的顶部。因此
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 }); |