etc./StackOverFlow

요소 외부의 클릭을 어떻게 감지합니까?

청렴결백한 만능 재주꾼 2021. 11. 11. 07:58
반응형

질문자 :Community Wiki


사용자가 이러한 메뉴의 헤드를 클릭할 때 완전히 표시되는 일부 HTML 메뉴가 있습니다. 사용자가 메뉴 영역 외부를 클릭할 때 이러한 요소를 숨기고 싶습니다.

jQuery로 이와 같은 것이 가능합니까?

 $("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus });


참고: stopPropagation 사용하면 DOM의 정상적인 이벤트 흐름이 중단되므로 피해야 합니다. 자세한 내용은 이 CSS 트릭 문서 를 참조하세요. 대신 이 방법을 사용하는 것이 좋습니다.

창을 닫는 문서 본문에 클릭 이벤트를 첨부합니다. 문서 본문에 대한 전파를 중지하는 별도의 클릭 이벤트를 컨테이너에 첨부합니다.

 $(window).click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); });

Community Wiki

document 에서 클릭 이벤트를 수신한 다음 .closest() #menucontainer 가 클릭된 요소의 조상 또는 대상이 아닌지 확인할 수 있습니다.

그렇지 않은 경우 클릭된 요소는 #menucontainer 외부에 있으므로 안전하게 숨길 수 있습니다.

 $(document).click(function(event) { var $target = $(event.target); if(!$target.closest('#menucontainer').length && $('#menucontainer').is(":visible")) { $('#menucontainer').hide(); } });

수정 – 2017-06-23

메뉴를 닫고 이벤트 수신을 중지하려는 경우 이벤트 리스너 이후를 정리할 수도 있습니다. 이 함수는 새로 생성된 리스너만 정리하고 document 다른 클릭 리스너는 보존합니다. ES2015 구문 사용:

 export function hideOnClickOutside(selector) { const outsideClickListener = (event) => { const $target = $(event.target); if (!$target.closest(selector).length && $(selector).is(':visible')) { $(selector).hide(); removeClickListener(); } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) }

수정 – 2018-03-11

jQuery를 사용하고 싶지 않은 사람들을 위해. 다음은 일반 바닐라JS(ECMAScript6)의 위 코드입니다.

 function hideOnClickOutside(element) { const outsideClickListener = event => { if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null element.style.display = 'none' removeClickListener() } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) } const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

참고: 이것은 jQuery 부분 대신 !element.contains(event.target) 를 사용하기 위한 Alex 주석을 기반으로 합니다.

그러나 element.closest() 는 이제 모든 주요 브라우저에서도 사용할 수 있습니다(W3C 버전은 jQuery 버전과 약간 다름). 폴리필은 여기에서 찾을 수 있습니다: Element.closest()

수정 – 2020-05-21

사용자가 요소 내부를 클릭하고 드래그할 수 있게 하려면 요소를 닫지 않고 요소 외부에서 마우스를 놓으십시오.

 ... let lastMouseDownX = 0; let lastMouseDownY = 0; let lastMouseDownWasOutside = false; const mouseDownListener = (event: MouseEvent) => { lastMouseDownX = event.offsetX lastMouseDownY = event.offsetY lastMouseDownWasOutside = !$(event.target).closest(element).length } document.addEventListener('mousedown', mouseDownListener);

그리고 outsideClickListener :

 const outsideClickListener = event => { const deltaX = event.offsetX - lastMouseDownX const deltaY = event.offsetY - lastMouseDownY const distSq = (deltaX * deltaX) + (deltaY * deltaY) const isDrag = distSq > 3 const isDragException = isDrag && !lastMouseDownWasOutside if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null element.style.display = 'none' removeClickListener() document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener() } }

Community Wiki

요소 외부의 클릭을 감지하는 방법은 무엇입니까?

이 질문이 인기 있고 답이 많은 이유는 매우 복잡하기 때문입니다. 거의 8년 동안 수십 가지의 답변을 받은 후 접근성에 대해 얼마나 신경을 쓰지 않았는지에 대해 진심으로 놀랐습니다.

사용자가 메뉴 영역 외부를 클릭할 때 이러한 요소를 숨기고 싶습니다.

이것은 고귀한 원인이며 실제 문제입니다. 대부분의 답변이 해결하려고 시도하는 것으로 보이는 질문 제목에는 불행한 청어가 포함되어 있습니다.

힌트: "클릭" 이라는 단어입니다!

실제로 클릭 핸들러를 바인딩하고 싶지는 않습니다.

클릭 핸들러를 바인딩하여 대화 상자를 닫는다면 이미 실패한 것입니다. 실패한 이유는 모든 사람이 click 이벤트를 트리거하는 것은 아니기 때문입니다. 마우스를 사용하지 않는 사용자는 Tab 키 를 눌러 대화 상자(그리고 팝업 메뉴는 틀림없이 대화 상자 유형임)를 벗어날 수 click 트리거하지 않고는 대화 상자 뒤에 있는 내용을 읽을 수 없습니다. 이벤트.

그럼 질문을 바꿔보겠습니다.

사용자가 대화를 마쳤을 때 대화 상자를 어떻게 닫습니까?

이것이 목표입니다. 불행히도 이제 우리는 userisfinishedwiththedialog 를 바인딩해야 하며 그 바인딩은 그렇게 간단하지 않습니다.

그러면 사용자가 대화 상자 사용을 완료했음을 어떻게 감지할 수 있습니까?

focusout 이벤트

포커스가 대화 상자를 벗어났는지 확인하는 것이 좋습니다.

힌트: blur 이벤트에 주의하십시오. 이벤트가 버블링 단계에 바인딩된 경우 blur

jQuery의 focusout 은 잘 될 것입니다. jQuery를 사용할 수 없는 경우 캡처 단계에서 blur

 element.addEventListener('blur', ..., true); // use capture: ^^^^

또한 많은 대화 상자의 경우 컨테이너가 포커스를 얻을 수 있도록 해야 합니다. tabindex="-1" 을 추가하면 탭 이동 흐름을 방해하지 않고 대화 상자가 동적으로 포커스를 받을 수 있습니다.

 $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on('focusout', function () { $(this).removeClass('active'); });
 div { display: none; } .active { display: block; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>


해당 데모로 1분 이상 플레이하면 문제가 빨리 보이기 시작해야 합니다.

첫 번째는 대화 상자의 링크를 클릭할 수 없다는 것입니다. 그것을 클릭하거나 탭을 시도하면 상호 작용이 일어나기 전에 대화 상자가 닫힙니다. 내부 요소에 초점을 focusin 이벤트가 다시 focusout 이벤트가 발생하기 때문입니다.

수정 사항은 이벤트 루프에서 상태 변경을 대기열에 넣는 것입니다. setImmediate(...) 를 사용하거나 setImmediate 지원하지 않는 브라우저의 setTimeout(..., 0) 을 사용하여 수행할 수 있습니다. focusin 의해 취소될 수 있습니다.

 $('.submenu').on({ focusout: function (e) { $(this).data('submenuTimer', setTimeout(function () { $(this).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function (e) { clearTimeout($(this).data('submenuTimer')); } }); 

 $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on({ focusout: function () { $(this).data('timer', setTimeout(function () { $(this).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('timer')); } });
 div { display: none; } .active { display: block; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>

두 번째 문제는 링크를 다시 눌러도 대화 상자가 닫히지 않는다는 것입니다. 이는 대화 상자가 포커스를 잃고 닫기 동작을 트리거한 후 링크 클릭이 대화 상자를 다시 열도록 트리거하기 때문입니다.

이전 문제와 마찬가지로 포커스 상태를 관리해야 합니다. 상태 변경이 이미 대기 중이라는 점을 감안할 때 대화 상자 트리거에서 포커스 이벤트를 처리하기만 하면 됩니다.

이것은 친숙하게 보일 것입니다.
 $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } }); 

 $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on({ focusout: function () { $(this).data('timer', setTimeout(function () { $(this).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('timer')); } }); $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } });
 div { display: none; } .active { display: block; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>


Esc

포커스 상태를 처리하는 것으로 끝났다고 생각했다면 사용자 경험을 단순화하기 위해 더 많은 것을 할 수 있습니다.

이것은 종종 "있으면 좋은" 기능이지만 어떤 종류의 모달이나 팝업이 있을 때 Esc 키를 눌러 닫는 것이 일반적입니다.

 keydown: function (e) { if (e.which === 27) { $(this).removeClass('active'); e.preventDefault(); } } 

 $('a').on('click', function () { $(this.hash).toggleClass('active').focus(); }); $('div').on({ focusout: function () { $(this).data('timer', setTimeout(function () { $(this).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('timer')); }, keydown: function (e) { if (e.which === 27) { $(this).removeClass('active'); e.preventDefault(); } } }); $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } });
 div { display: none; } .active { display: block; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>


대화 상자 내에 초점을 맞출 수 있는 요소가 있다는 것을 알고 있다면 대화 상자에 직접 초점을 맞출 필요가 없습니다. 메뉴를 작성하는 경우 대신 첫 번째 메뉴 항목에 초점을 맞출 수 있습니다.

 click: function (e) { $(this.hash) .toggleClass('submenu--active') .find('a:first') .focus(); e.preventDefault(); } 

 $('.menu__link').on({ click: function (e) { $(this.hash) .toggleClass('submenu--active') .find('a:first') .focus(); e.preventDefault(); }, focusout: function () { $(this.hash).data('submenuTimer', setTimeout(function () { $(this.hash).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('submenuTimer')); } }); $('.submenu').on({ focusout: function () { $(this).data('submenuTimer', setTimeout(function () { $(this).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data('submenuTimer')); }, keydown: function (e) { if (e.which === 27) { $(this).removeClass('submenu--active'); e.preventDefault(); } } });
 .menu { list-style: none; margin: 0; padding: 0; } .menu:after { clear: both; content: ''; display: table; } .menu__item { float: left; position: relative; } .menu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .menu__link:hover, .menu__link:focus { background-color: black; color: lightblue; } .submenu { border: 1px solid black; display: none; left: 0; list-style: none; margin: 0; padding: 0; position: absolute; top: 100%; } .submenu--active { display: block; } .submenu__item { width: 150px; } .submenu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .submenu__link:hover, .submenu__link:focus { background-color: black; color: lightblue; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <ul class="menu"> <li class="menu__item"> <a class="menu__link" href="#menu-1">Menu 1</a> <ul class="submenu" id="menu-1" tabindex="-1"> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li> </ul> </li> <li class="menu__item"> <a class="menu__link" href="#menu-2">Menu 2</a> <ul class="submenu" id="menu-2" tabindex="-1"> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li> </ul> </li> </ul> lorem ipsum <a href="http://example.com/">dolor</a> sit amet.


WAI-ARIA 역할 및 기타 접근성 지원

이 답변은 희망이 기능에 대한 접근 키보드와 마우스 지원의 기초를 다루고 있지만, 이미 꽤 상당한 규모의 나는이 모든 논의를 피하기 위해거야 WAI-ARIA 역할과 특성을 하지만 내가보기 구현 세부 사항에 대한 사양을 참조하는 것이 좋습니다, 그들이 사용해야 하는 역할과 기타 적절한 속성.


Community Wiki

여기에 있는 다른 솔루션은 저에게 효과가 없었으므로 다음을 사용해야 했습니다.

 if(!$(event.target).is('#foo')) { // hide menu }

편집: 일반 Javascript 변형(2021-03-31)

이 방법을 사용하여 외부를 클릭할 때 드롭다운 메뉴 닫기를 처리했습니다.

먼저 구성 요소의 모든 요소에 대한 사용자 정의 클래스 이름을 만들었습니다. 이 클래스 이름은 메뉴 위젯을 구성하는 모든 요소에 추가됩니다.

 const className = `dropdown-${Date.now()}-${Math.random() * 100}`;

클릭한 요소의 클래스 이름과 클릭을 확인하는 함수를 만듭니다. 클릭한 요소에 위에서 생성한 사용자 정의 클래스 이름이 포함되어 있지 않으면 show 플래그를 false 설정해야 하며 메뉴가 닫힙니다.

 const onClickOutside = (e) => { if (!e.target.className.includes(className)) { show = false; } };

그런 다음 클릭 핸들러를 창 개체에 연결했습니다.

 // add when widget loads window.addEventListener("click", onClickOutside);

... 그리고 마지막으로 가사도우미

 // remove listener when destroying the widget window.removeEventListener("click", onClickOutside);

Community Wiki

메뉴를 열 때 본문에 클릭 이벤트를 첨부한다는 점을 제외하면 Eran의 예와 유사하게 작동하는 응용 프로그램이 있습니다.

 $('#menucontainer').click(function(event) { $('html').one('click',function() { // Hide the menus }); event.stopPropagation(); });

jQuery의 one() 함수 에 대한 추가 정보


Community Wiki

event.composedPath() 사용할 수 있습니다.

발신: https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

Event 인터페이스의 configuredPath() 메서드는 이벤트의 경로를 반환합니다. 이 경로는 리스너가 호출될 객체의 배열입니다.

 const target = document.querySelector('#myTarget') document.addEventListener('click', (event) => { const withinBoundaries = event.composedPath().includes(target) if (withinBoundaries) { target.innerText = 'Click happened inside element' } else { target.innerText = 'Click happened **OUTSIDE** element' } })
 /* just to make it good looking. you don't need this */ #myTarget { margin: 50px auto; width: 500px; height: 500px; background: gray; border: 10px solid black; }
 <div id="myTarget"> click me (or not!) </div>


Community Wiki

연구 후 세 가지 작업 솔루션을 찾았습니다(참조용 페이지 링크를 잊었습니다).

첫 번째 솔루션

 <script> //The good thing about this solution is it doesn't stop event propagation. var clickFlag = 0; $('body').on('click', function () { if(clickFlag == 0) { console.log('hide element here'); /* Hide element here */ } else { clickFlag=0; } }); $('body').on('click','#testDiv', function (event) { clickFlag = 1; console.log('showed the element'); /* Show the element */ }); </script>

두 번째 솔루션

 <script> $('body').on('click', function(e) { if($(e.target).closest('#testDiv').length == 0) { /* Hide dropdown here */ } }); </script>

세 번째 솔루션

 <script> var specifiedElement = document.getElementById('testDiv'); document.addEventListener('click', function(event) { var isClickInside = specifiedElement.contains(event.target); if (isClickInside) { console.log('You clicked inside') } else { console.log('You clicked outside') } }); </script>

Community Wiki

$("#menuscontainer").click(function() { $(this).focus(); }); $("#menuscontainer").blur(function(){ $(this).hide(); });

나를 위해 잘 작동합니다.


Community Wiki

이제 이를 위한 플러그인이 있습니다. 외부 이벤트 ( 블로그 게시물 )

다음은 WLOG(clickoutside 핸들러)가 요소에 바인딩될 때 발생합니다.

  • 요소는 clickoutside 핸들러가 있는 모든 요소를 보유하는 배열에 추가됩니다.
  • ( 네임스페이스가 있는 ) 클릭 핸들러가 문서에 바인딩되어 있습니다(아직 없는 경우).
  • 문서에서 모든 클릭의 clickoutside 이벤트 같지 않은 그 배열의 해당 요소 또는 클릭 - 이벤트 대상의 부모 트리거
  • 또한 clickoutside 이벤트의 event.target은 사용자가 클릭한 요소로 설정됩니다(따라서 사용자가 외부를 클릭했을 뿐만 아니라 무엇을 클릭했는지도 알 수 있음)

따라서 전파에서 이벤트가 중지되지 않으며 외부 처리기가 있는 요소 "위에서" 추가 클릭 처리기를 사용할 수 있습니다.


Community Wiki

이것은 나를 위해 완벽하게 일했습니다 !!

 $('html').click(function (e) { if (e.target.id == 'YOUR-DIV-ID') { //do something } else { //do something } });

Community Wiki

상황에 대한 간단한 솔루션은 다음과 같습니다.

 $(document).mouseup(function (e) { var container = $("YOUR SELECTOR"); // Give you class or ID if (!container.is(e.target) && // If the target of the click is not the desired div or section container.has(e.target).length === 0) // ... nor a descendant-child of the container { container.hide(); } });

위의 스크립트는 div 클릭 이벤트 외부에서 div

자세한 내용은 다음 블로그를 참조하십시오. http://www.codecanal.com/detect-click-outside-div-using-javascript/


Community Wiki

사용자가 외부를 클릭할 때 메뉴를 닫는 것이 정말로 필요한 것은 아니라고 생각합니다. 필요한 것은 사용자가 페이지의 아무 곳이나 클릭할 때 메뉴가 닫히는 것입니다. 메뉴를 클릭하거나 메뉴를 끄면 닫히겠죠?

위의 만족스러운 답변을 찾지 못해 요 전에 이 블로그 게시물 을 작성하게 되었습니다. 좀 더 현학적인 경우 주의해야 할 문제가 많이 있습니다.

  1. 클릭 시 body 요소에 click 이벤트 핸들러를 연결하는 경우 메뉴를 닫고 이벤트 바인딩을 해제하기 전에 두 번째 클릭을 기다려야 합니다. 그렇지 않으면 메뉴를 연 클릭 이벤트가 메뉴를 닫아야 하는 리스너까지 버블링됩니다.
  2. 클릭 이벤트에 event.stopPropogation()을 사용하는 경우 페이지의 다른 요소에는 아무데서나 클릭하여 닫기 기능이 있을 수 없습니다.
  3. 클릭 이벤트 핸들러를 body 요소에 무기한 연결하는 것은 성능이 좋은 솔루션이 아닙니다.
  4. 이벤트의 대상과 그 부모를 핸들러 작성자와 비교하면 원하는 것은 클릭할 때 메뉴를 닫는 것이고 실제로 원하는 것은 페이지의 아무 곳이나 클릭할 때 닫는 것이라고 가정합니다.
  5. body 요소에서 이벤트를 수신하면 코드가 더 부서지기 쉽습니다. 이렇게 순진하게 스타일링하면 문제가 해결됩니다. body { margin-left:auto; margin-right: auto; width:960px;}

Community Wiki

다른 포스터가 말했듯이 특히 표시하는 요소(이 경우 메뉴)에 대화형 요소가 있는 경우 문제가 많습니다. 다음 방법이 상당히 강력하다는 것을 알았습니다.

 $('#menuscontainer').click(function(event) { //your code that shows the menus fully //now set up an event listener so that clicking anywhere outside will close the menu $('html').click(function(event) { //check up the tree of the click target to check whether user has clicked outside of menu if ($(event.target).parents('#menuscontainer').length==0) { // your code to hide menu //this event listener has done its job so we can unbind it. $(this).unbind(event); } }) });

Community Wiki

창 클릭 이벤트 대상을 확인하고(다른 곳에서 캡처되지 않는 한 창으로 전파되어야 함) 메뉴 요소가 아닌지 확인합니다. 그렇지 않으면 메뉴 밖에 있는 것입니다.

또는 클릭 위치를 확인하고 메뉴 영역에 포함되어 있는지 확인합니다.


Community Wiki

솔루션1

부작용이 있을 수 있는 event.stopPropagation()을 사용하는 대신 간단한 플래그 변수를 정의하고 if 조건을 하나 추가하면 됩니다. 나는 이것을 테스트했고 stopPropagation의 부작용 없이 제대로 작동했습니다.

 var flag = "1"; $('#menucontainer').click(function(event){ flag = "0"; // flag 0 means click happened in the area where we should not do any action }); $('html').click(function() { if(flag != "0"){ // Hide the menus if visible } else { flag = "1"; } });

솔루션2

간단한 if 조건으로:

 $(document).on('click', function(event){ var container = $("#menucontainer"); if (!container.is(event.target) && // If the target of the click isn't the container... container.has(event.target).length === 0) // ... nor a descendant of the container { // Do whatever you want to do when click is outside the element } });

Community Wiki

나는 다음과 같이 성공했습니다.

 var $menuscontainer = ...; $('#trigger').click(function() { $menuscontainer.show(); $('body').click(function(event) { var $target = $(event.target); if ($target.parents('#menuscontainer').length == 0) { $menuscontainer.hide(); } }); });

논리는 다음과 같습니다. #menuscontainer 가 표시되면 대상(클릭의)이 자식이 아닌 경우에만 #menuscontainer 를 숨기는 본문에 클릭 핸들러를 바인딩합니다.


Community Wiki

나는 아무도 실제로 focusout 이벤트를 인정하지 않았다는 것에 놀랐습니다.

 var button = document.getElementById('button'); button.addEventListener('click', function(e){ e.target.style.backgroundColor = 'green'; }); button.addEventListener('focusout', function(e){ e.target.style.backgroundColor = ''; });
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <button id="button">Click</button> </body> </html>


Community Wiki

이벤트에는 "트리 순서의 모든 상위 항목의 정적 순서 목록"인 요소의 event.path라는 속성이 있습니다. 이벤트가 특정 DOM 요소 또는 그 자식 중 하나에서 발생했는지 확인하려면 해당 특정 DOM 요소의 경로를 확인하면 됩니다. some 함수에서 요소 검사를 OR 하여 여러 요소를 검사하는 데 사용할 수도 있습니다.

 $("body").click(function() { target = document.getElementById("main"); flag = event.path.some(function(el, i, arr) { return (el == target) }) if (flag) { console.log("Inside") } else { console.log("Outside") } });
 #main { display: inline-block; background:yellow; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="main"> <ul> <li>Test-Main</li> <li>Test-Main</li> <li>Test-Main</li> <li>Test-Main</li> <li>Test-Main</li> </ul> </div> <div id="main2"> Outside Main </div>

따라서 귀하의 경우에는

 $("body").click(function() { target = $("#menuscontainer")[0]; flag = event.path.some(function(el, i, arr) { return (el == target) }); if (!flag) { // Hide the menus } });

Community Wiki

변형:

 var $menu = $('#menucontainer'); $(document).on('click', function (e) { // If element is opened and click target is outside it, hide it if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) { $menu.hide(); } });

이벤트 전파 를 중지하는 데 문제가 없으며 첫 번째 메뉴가 열려 있는 동안 두 번째 메뉴를 클릭하면 stopPropagation 솔루션에서 첫 번째 메뉴가 열려 있는 동일한 페이지에서 여러 메뉴를 더 잘 지원합니다.


Community Wiki

일부 jQuery 캘린더 플러그인에서 이 방법을 찾았습니다.

 function ClickOutsideCheck(e) { var el = e.target; var popup = $('.popup:visible')[0]; if (popup==undefined) return true; while (true){ if (el == popup ) { return true; } else if (el == document) { $(".popup").hide(); return false; } else { el = $(el).parent()[0]; } } }; $(document).bind('mousedown.popup', ClickOutsideCheck);

Community Wiki

다음은 미래의 시청자를 위한 바닐라 JavaScript 솔루션입니다.

문서 내의 요소를 클릭할 때 클릭한 요소의 ID가 토글되거나 숨겨진 요소가 숨겨지지 않고 숨겨진 요소에 클릭된 요소가 포함되지 않은 경우 해당 요소를 토글합니다.

 (function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })(); 

 (function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })();
 <a href="javascript:void(0)" id="toggle">Toggle Hidden Div</a> <div id="hidden" style="display: none;">This content is normally hidden. click anywhere other than this content to make me disappear</div>

동일한 페이지에 여러 토글을 사용하려는 경우 다음과 같이 사용할 수 있습니다.

  1. 접을 수 있는 항목에 hidden 클래스 이름을 추가합니다.
  2. 문서 클릭 시 클릭된 요소를 포함하지 않고 숨겨지지 않은 모든 숨겨진 요소를 닫습니다.
  3. 클릭한 요소가 토글이면 지정된 요소를 토글합니다.

 (function () { "use strict"; var hiddenItems = document.getElementsByClassName('hidden'), hidden; document.addEventListener('click', function (e) { for (var i = 0; hidden = hiddenItems[i]; i++) { if (!hidden.contains(e.target) && hidden.style.display != 'none') hidden.style.display = 'none'; } if (e.target.getAttribute('data-toggle')) { var toggle = document.querySelector(e.target.getAttribute('data-toggle')); toggle.style.display = toggle.style.display == 'none' ? 'block' : 'none'; } }, false); })();
 <a href="javascript:void(0)" data-toggle="#hidden1">Toggle Hidden Div</a> <div class="hidden" id="hidden1" style="display: none;" data-hidden="true">This content is normally hidden</div> <a href="javascript:void(0)" data-toggle="#hidden2">Toggle Hidden Div</a> <div class="hidden" id="hidden2" style="display: none;" data-hidden="true">This content is normally hidden</div> <a href="javascript:void(0)" data-toggle="#hidden3">Toggle Hidden Div</a> <div class="hidden" id="hidden3" style="display: none;" data-hidden="true">This content is normally hidden</div>


Community Wiki

IE 및 FF 3.*용으로 스크립팅하고 특정 상자 영역 내에서 클릭이 발생했는지 알고 싶다면 다음과 같이 사용할 수도 있습니다.

 this.outsideElementClick = function(objEvent, objElement){ var objCurrentElement = objEvent.target || objEvent.srcElement; var blnInsideX = false; var blnInsideY = false; if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right <= objElement.getBoundingClientRect().right) blnInsideX = true; if (objCurrentElement.getBoundingClientRect().top >= objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom <= objElement.getBoundingClientRect().bottom) blnInsideY = true; if (blnInsideX && blnInsideY) return false; else return true;}

Community Wiki

흐름 중단, 흐림/초점 이벤트 또는 기타 까다로운 기술을 사용하는 대신 이벤트 흐름을 요소의 친족과 일치시키기만 하면 됩니다.

 $(document).on("click.menu-outside", function(event){ // Test if target and it's parent aren't #menuscontainer // That means the click event occur on other branch of document tree if(!$(event.target).parents().andSelf().is("#menuscontainer")){ // Click outisde #menuscontainer // Hide the menus (but test if menus aren't already hidden) } });

이벤트 리스너 외부 클릭을 제거하려면 다음을 수행하십시오.

 $(document).off("click.menu-outside");

Community Wiki

사용하다:

 var go = false; $(document).click(function(){ if(go){ $('#divID').hide(); go = false; } }) $("#divID").mouseover(function(){ go = false; }); $("#divID").mouseout(function (){ go = true; }); $("btnID").click( function(){ if($("#divID:visible").length==1) $("#divID").hide(); // Toggle $("#divID").show(); });

Community Wiki

여기에 궁금한 사람이 javascript 솔루션(es6)이 있는 경우:

 window.addEventListener('mouseup', e => { if (e.target != yourDiv && e.target.parentNode != yourDiv) { yourDiv.classList.remove('show-menu'); //or yourDiv.style.display = 'none'; } })

및 es5, 다음과 같은 경우를 대비하여:

 window.addEventListener('mouseup', function (e) { if (e.target != yourDiv && e.target.parentNode != yourDiv) { yourDiv.classList.remove('show-menu'); //or yourDiv.style.display = 'none'; }

});


Community Wiki

다음은 순수한 자바 스크립트의 간단한 솔루션입니다. ES6의 최신 버전입니다 .

 var isMenuClick = false; var menu = document.getElementById('menuscontainer'); document.addEventListener('click',()=>{ if(!isMenuClick){ //Hide the menu here } //Reset isMenuClick isMenuClick = false; }) menu.addEventListener('click',()=>{ isMenuClick = true; })

Community Wiki

아래 스크립트를 사용하고 jQuery로 완료했습니다.

 jQuery(document).click(function(e) { var target = e.target; //target div recorded if (!jQuery(target).is('#tobehide') ) { jQuery(this).fadeOut(); //if the click element is not the above id will hide } })

아래에서 HTML 코드를 찾으십시오.

 <div class="main-container"> <div> Hello I am the title</div> <div class="tobehide">I will hide when you click outside of me</div> </div>

여기 에서 튜토리얼을 읽을 수 있습니다


Community Wiki

네이티브 JS API 가장 가까운 방법을 사용하는 2020 솔루션.

 document.addEventListener('click', ({ target }) => { if (!target.closest('.el1, .el2, #el3')) { alert('click outside') } })

Community Wiki

$(document).click(function() { $(".overlay-window").hide(); }); $(".overlay-window").click(function() { return false; });

문서를 클릭하면 동일한 요소를 클릭하지 않는 한 주어진 요소를 숨깁니다.


Community Wiki

문서에 클릭 이벤트 리스너를 연결합니다. 이벤트 리스너 내에서 이벤트 객체 , 특히 event.target 을 보고 어떤 요소가 클릭되었는지 확인할 수 있습니다.

 $(document).click(function(e){ if ($(e.target).closest("#menuscontainer").length == 0) { // .closest can help you determine if the element // or one of its ancestors is #menuscontainer console.log("hide"); } });

Community Wiki

출처 : http:www.stackoverflow.com/questions/152975/how-do-i-detect-a-click-outside-an-element

반응형