나는 모든 곳에서 좋은 솔루션을 찾았지만 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 요소 인 속성이 있습니다. 이를 통해 자신을 확인하고 문서 요소 중 하나가 감시 요소 인 경우 해당 부모를 문서 요소까지 걸어갑니다.
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이 아닐 때 자식이 클릭되지만 부모 중 하나는 감시 된 요소입니다 (단순히 레벨을 계산합니다). 요소가 있는지 여부에 관계없이 for 절 내부에서 처리기를 반환하지 않도록 부울 var를 사용할 수도 있습니다. 내 예는 아무것도 일치하지 않을 때 처리기가 완료되는 것으로 제한합니다.
브라우저 간 호환성을 추가하면 일반적으로 다음과 같이합니다.
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);
}
};
이것은 이벤트 리스너 / 핸들러를 연결하기위한 브라우저 간 호환 코드이며, thisIE에서 재 작성 을 포함 하여 jQuery가 이벤트 핸들러에 대해 수행하는 것처럼 요소가됩니다. jQuery를 염두에 두어야 할 인수가 많이 있습니다.)
target속성 (메타 딩에서 말했듯이 가장 안쪽의 DOM 요소)과 모든 부모 요소를 확인합니다. 사용자가 내부를 클릭했음을 의미하는 감시 된 요소에 도달하거나 외부를 클릭 한 문서 요소에 도달합니다. 또는 두 개의 클릭 리스너를 추가 할 수 있습니다. 하나는 문서 요소에, 다른 하나는 감시 된 요소에 추가 할 수 있습니다.이 경우 event.stopPropagation()/ 를 사용 cancelBubble하여 문서 요소의 리스너는 감시 된 요소 외부의 클릭에 의해서만 트리거됩니다.
for. 호기심에서 변수의 요소를 이벤트의 대상과 비교하지 않을 이유가 있습니까 (엄격한 비교 사용)?
외부를 클릭하여 요소를 숨기려면 보통 다음과 같은 간단한 코드를 적용합니다.
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);
이 문제에 대한 또 다른 매우 간단하고 빠른 접근 방식 path은 리스너가 반환 한 이벤트 객체에 배열을 매핑하는 것 입니다. 요소 의 id또는 class이름이 배열의 이름 중 하나와 일치하면 클릭이 요소 내부에있는 것입니다.
(이 솔루션은 요소를 직접 가져 오지 않으려는 경우 유용 할 수 있습니다 (예 : document.getElementById('...')ssr ..의 reactjs / nextjs 앱).
다음은 그 예입니다.
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에서 재귀 적으로 이동하여 대상이 포함되어 있는지 여부를 확인합니다. 반응 프로젝트 중 하나에서 사용했지만 설정된 상태에서 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')
}
})