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


질문

 

나는 사용자 가이 메뉴의 머리를 클릭하면 내가 완전히 보여주는 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();
});


답변

문서에서 클릭 이벤트를 청취 한 다음 #menucontainer가 .cloSest ()를 사용하여 클릭 된 요소의 조상이나 대상이 아닌지 확인할 수 있습니다.

그렇지 않으면 클릭 된 요소가 #menucontainer 밖에 있고 안전하게 숨길 수 있습니다.

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

편집 - 2017-06-23.

메뉴를 기각하고 이벤트 듣기를 중지하려는 경우 이벤트 리스너를 정리할 수도 있습니다.이 기능은 새로 생성 된 수신기 만 정리하여 다른 클릭 수신기를 문서에서 보존합니다.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를 사용하고 싶지 않은 사람들을 위해.다음은 일반 Vanillajs (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 부분 대신 Alex Comment에 대한 알렉스 코멘트를 기반으로합니다.

그러나 element.closest ()는 이제 모든 주요 브라우저에서도 사용할 수 있습니다 (W3C 버전은 jQuery One에서 약간 다릅니다). 폴리필은 여기에서 찾을 수 있습니다 : 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);

아웃시시시클리 스테이너에서 :

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()
        }
    }


답변

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

이 질문이 너무 인기가 있고 많은 대답이 너무 많은 답변은 매우 복잡하다는 이유가 있습니다.거의 8 년 동안 수십 개의 답변이 끝난 후에 나는 접근성에 얼마나 작은 보살핌이 주어 졌는지를 알게되어 놀라게 놀랐습니다.

사용자가 메뉴 영역 밖에있는 사용자가 클릭하면 이러한 요소를 숨기고 싶습니다.

이것은 고귀한 원인이며 실제 문제입니다.질문의 제목 - 대부분의 답변이 불행한 붉은 청어를 포함하는 것처럼 보이는 것입니다.

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

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

바인딩하는 경우 핸들러를 클릭하여 대화 상자를 닫으려면 이미 실패했습니다.실패한 이유는 모든 사람이 이벤트를 클릭하는 것은 아닙니다.마우스를 사용하지 않는 사용자는 탭을 눌러 대화 상자 (및 팝업 메뉴가 틀림없이 대화 상자 유형)를 이스케이프로 처리 할 수 있으며,이어서 클릭을 트리거하지 않고 대화 상자 뒤에있는 콘텐츠를 읽을 수 없습니다이벤트.

그럼 질문을 다시 말하자.

사용자가 완료되면 대화 상자가 어떻게 닫습니까?

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

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

포커스 이벤트

좋은 시작은 중점이 대화 상자를 남겨 두는지 확인하는 것입니다.

힌트 : 흐림 이벤트에주의하십시오. 이벤트가 버블 링 단계에 묶여있는 경우 흐림 효과가 전파되지 않습니다!

jQuery의 집중력은 괜찮을 것입니다.jQuery를 사용할 수 없으면 캡처 단계에서 흐림을 사용할 수 있습니다.

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

또한 많은 대화 상자에 대해 컨테이너가 초점을 맞출 수 있도록해야합니다.탭 흐름을 방해하지 않고 대화 상자를 동적으로 수신하는 대화 상자가 동적으로 수신하도록 addindex = "-1"을 추가하십시오.

$ ( 'a'). ( '클릭', 함수 () { $ (this.hash) .togGleclass ( '활성'). 초점 (); }); $ ( 'div'). on ( 'FocusOut', function () { $ (이) .removeClass ( 'active'); }); div { 디스플레이 : 없음; } .활동적인 { 디스플레이 : 블록; }

메뉴를 열 때 클릭 이벤트를 몸에 첨부 할 때 Eran의 예제와 비슷하게 작동하는 응용 프로그램이 있습니다.

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

  event.stopPropagation();
});

jQuery의 one () 기능에 대한 자세한 정보



답변

2020이며 EventComposedPath ()를 사용할 수 있습니다.

에서 : https://developer.mozilla.org/en-us/docs/web/api/event/composedpath.

이벤트 인터페이스의 composedpath () 메서드는 리스너가 호출 될 오브젝트의 배열 인 이벤트 경로를 반환합니다.

const target = document.querySelector ( '# myTarget') document.addeventListener ( '클릭', (이벤트) => { const interboundaries = EventComposedPath (). 포함 (대상) if (in boundaries) { target.innertext = '클릭 된 내부 요소'클릭 } 또 다른 { target.innerText = '클릭 일어났습니다 ** 외부 ** 요소' } }) / * 그냥 잘 보이게하십시오.당신은 이것을 필요로하지 않습니다 * / #mytarget { 마진 : 50px 자동; 너비 : 500px; 높이 : 500px; 배경 : 회색; 테두리 : 10px 솔리드 블랙; }

나를 클릭하십시오 (또는 그렇지 않음).

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