私は絶対位置のdivを持っており、マウスがその上に移動したとき、およびマウスが離れたときを追跡しようとしています。残念ながら、ボックス内のテキストをクリックすると、時々mouseleaveイベントがトリガーされます。
デモ: 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;
}
これはバグのようです(Chromeでクリックすると、マウスを押し下げたり、上げたりすると、お互いに急速に発生します)。
イベントが発生したときにマウスがまだ要素上にあるかどうかを確認して、この問題を回避することをお勧めします。
tooltip.onmouseleave = (e) => {
if (tooltip === document.elementFromPoint(e.clientX, e.clientY)) {
console.log('false positive');
return;
}
console.log('tooltip mouse OUT')
}
欠点は、ブラウザウィンドウがフォーカスを失うと、誤検知と見なされることです。それが問題である場合は、 この答え を確認してください。
以前はここで回答とコメントを見ていましたが、最近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
がトリガーされるようです。それを調べる必要があります
私もこのバグに遭遇しました。私の場合、ラベルでラップされたチェックボックスをリストに追加し、リストをdivでラップしました。 <hr>
タグのリストアイテムもいくつか使用しました。チェックボックスとラベルをすばやくクリックすると、ラッピングdivでmouseleave
イベントがトリガーされることがあります。クリックされたすべての要素がdiv.wrapper
の子であるため、これは発生しません。
...
wrapper.addEventListener(
'mouseleave',
(e) => {
logger('mouseleave fired');
console.log('mouseleave fired', e);
},
false
);
...
これが複製のGIFです。手がかり領域(ある程度の強度と動きが許可されている)内をクリックし、ラベルと入力ボックスからのイベントをクリックすると、2つのmouseleaveイベントが発生しますエラーが発生し、マウスが本当に青い領域を離れると、3分の1になります。
@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;
}