私はどこでも良い解決策を探しましたが、jQueryを使用しない解決策を見つけることができません。
要素の外側のクリックを検出するためのクロスブラウザー、通常の方法(奇妙なハッキングやコードの解読が簡単でない)はありますか(子がある場合とない場合があります)?
私はどこでも良い解決策を探しましたが、jQueryを使用しない解決策を見つけることができません。
要素の外側のクリックを検出するためのクロスブラウザー、通常の方法(奇妙なハッキングやコードの解読が簡単でない)はありますか(子がある場合とない場合があります)?
回答:
イベントリスナーをに追加し、documentを使用Node.contains()して、イベントのターゲット(最も内側にクリックされた要素)が指定された要素内にあるかどうかを確認します。IE5でも動作します
var specifiedElement = document.getElementById('a');
//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (!isClickInside) {
//the click was outside the specifiedElement, do something
}
});
クリックイベントはドキュメントレベルで処理する必要があります。イベントオブジェクトには、targetクリックされた最も内側のDOM要素であるプロパティがあります。これを使用して、自分自身をチェックし、その親の1つが監視対象の要素である場合は、ドキュメント要素までその親をたどります。
jsFiddleの例を参照してください
document.addEventListener("click", function (e) {
var level = 0;
for (var element = e.target; element; element = element.parentNode) {
if (element.id === 'x') {
document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked";
return;
}
level++;
}
document.getElementById("out").innerHTML = "not x clicked";
});
いつものように、これはaddEventListener / attachEventのため、クロスバッドブラウザー互換ではありませんが、このように機能します。
event.targetでない場合、子がクリックされますが、その親の1つは監視された要素です(私は単にこれのレベルを数えています)。また、要素が見つかったかどうかに関係なく、for句内からハンドラーを返さないブール変数を使用することもできます。私の例は、何も一致しない場合にのみハンドラーが終了するように制限しています。
クロスブラウザの互換性を追加して、私は通常次のようにしています:
var addEvent = function (element, eventName, fn, useCapture) {
if (element.addEventListener) {
element.addEventListener(eventName, fn, useCapture);
}
else if (element.attachEvent) {
element.attachEvent(eventName, function (e) {
fn.apply(element, arguments);
}, useCapture);
}
};
これはthis、jQueryがイベントハンドラーに対して行うように、IEでの包括的書き換えを含むイベントリスナー/ハンドラーを要素としてアタッチするためのブラウザー間互換コードです。jQueryのいくつかのビットを念頭に置くための議論はたくさんあります;)
targetプロパティ(メタディングが言うように、最も内側のDOM要素になります)とそのすべての親要素を確認します。監視対象要素に到達するか、つまりユーザーがその内部をクリックしたか、ドキュメント要素に到達します。この場合、ユーザーは外部をクリックします。または、2つのクリックリスナーを追加することもできます。1つはドキュメント要素に、もう1つは監視要素に追加します。これはevent.stopPropagation()/を使用cancelBubbleして、ドキュメント要素のリスナーが監視要素の外側のクリックによってのみトリガーされるようにします。
for。好奇心から、変数の要素をイベントのターゲットと比較しない理由はありますか(厳密な比較を使用)?
これはどう:
document.onclick = function(event){
var hasParent = false;
for(var node = event.target; node != document.body; node = node.parentNode)
{
if(node.id == 'div1'){
hasParent = true;
break;
}
}
if(hasParent)
alert('inside');
else
alert('outside');
}
要素の外側をクリックして要素を非表示にするには、通常、次のような単純なコードを適用します。
var bodyTag = document.getElementsByTagName('body');
var element = document.getElementById('element');
function clickedOrNot(e) {
if (e.target !== element) {
// action in the case of click outside
bodyTag[0].removeEventListener('click', clickedOrNot, true);
}
}
bodyTag[0].addEventListener('click', clickedOrNot, true);
この問題に対するもう1つの非常に単純で迅速なアプローチは、の配列をpathリスナーから返されたイベントオブジェクトにマップすることです。要素のidorclass名が配列内の名前のいずれかと一致する場合、クリックは要素内にあります。
(このソリューションは、要素を直接取得したくない場合に役立ちます(たとえばdocument.getElementById('...')、reactjs / nextjsアプリ、ssr ..など)。
次に例を示します。
document.addEventListener('click', e => {
let clickedOutside = true;
e.path.forEach(item => {
if (!clickedOutside)
return;
if (item.className === 'your-element-class')
clickedOutside = false;
});
if (clickedOutside)
// Make an action if it's clicked outside..
});
この回答がお役に立てば幸いです。(私の解決策が良い解決策ではない場合、または改善すべき点がある場合はお知らせください。)
より良い方法を見つけるために、私はそれについて多くの研究をしました。JavaScriptメソッド.containsは、DOMで再帰的に移動して、ターゲットが含まれているかどうかを確認します。反応プロジェクトの1つで使用しましたが、セット状態で反応DOMが変更されると、.containsメソッドが機能しません。だから私はこの解決策を思いついた
//Basic Html snippet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="mydiv">
<h2>
click outside this div to test
</h2>
Check click outside
</div>
</body>
</html>
//Implementation in Vanilla javaScript
const node = document.getElementById('mydiv')
//minor css to make div more obvious
node.style.width = '300px'
node.style.height = '100px'
node.style.background = 'red'
let isCursorInside = false
//Attach mouseover event listener and update in variable
node.addEventListener('mouseover', function() {
isCursorInside = true
console.log('cursor inside')
})
/Attach mouseout event listener and update in variable
node.addEventListener('mouseout', function() {
isCursorInside = false
console.log('cursor outside')
})
document.addEventListener('click', function() {
//And if isCursorInside = false it means cursor is outside
if(!isCursorInside) {
alert('Outside div click detected')
}
})