HTML 메뉴가 있는데 사용자가이 메뉴의 헤드를 클릭하면 완전히 표시됩니다. 사용자가 메뉴 영역 바깥을 클릭하면 이러한 요소를 숨기고 싶습니다.
jQuery로 이와 같은 것이 가능합니까?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
답변
참고 : 사용
stopEventPropagation()
은 DOM에서 정상적인 이벤트 흐름을 방해하므로 피해야합니다. 자세한 내용은 이 기사 를 참조하십시오. 사용을 고려 이 방법을 대신
클릭 이벤트를 문서 본문에 첨부하여 창을 닫습니다. 별도의 클릭 이벤트를 컨테이너에 첨부하여 문서 본문으로의 전파를 중지하십시오.
$(window).click(function() {
//Hide the menus if visible
});
$('#menucontainer').click(function(event){
event.stopPropagation();
});
답변
클릭 이벤트를 수신 document
한 다음 #menucontainer
을 사용하여 클릭 한 요소의 조상 또는 대상이 아닌지 확인할 수 있습니다 .closest()
.
그렇지 않은 경우 클릭 한 요소가 외부에 #menucontainer
있으며 안전하게 숨길 수 있습니다.
$(document).click(function(event) {
$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) => {
$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
참고 :
이것은 !element.contains(event.target)
jQuery 부분 대신 사용하기 위해 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()
}
}
답변
요소 외부의 클릭을 감지하는 방법은 무엇입니까?
이 질문이 인기가 많고 답변이 많은 이유는 매우 복잡하기 때문입니다. 거의 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 분 이상 플레이하면 문제를 빨리보기 시작해야합니다.
첫 번째는 대화 상자의 링크를 클릭 할 수 없다는 것입니다. 해당 탭이나 탭을 클릭하면 상호 작용이 시작되기 전에 대화 상자가 닫힙니다. 내부 요소에 초점을 맞추면 이벤트가 다시 focusout
트리거되기 전에 이벤트가 트리거되기 때문 focusin
입니다.
수정은 이벤트 루프에서 상태 변경을 큐에 넣는 것입니다. 이것은 사용하여 수행 할 수 있습니다 setImmediate(...)
, 또는 setTimeout(..., 0)
지원하지 않는 브라우저를위한 setImmediate
. 대기열에 들어간 후에는 다음에 의해 취소 될 수 있습니다 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({
focusout: function () {
$(this.hash).data('timer', setTimeout(function () {
$(this.hash).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this.hash).data('timer'));
}
});
Esc 키
포커스 상태를 처리하여 완료했다고 생각되면 사용자 경험을 단순화하기 위해 더 많은 것을 할 수 있습니다.
이것은 종종 “좋은”기능이지만, 모달이나 팝업이있을 때 Esc키가 닫히는 것이 일반적입니다.
keydown: function (e) {
if (e.which === 27) {
$(this).removeClass('active');
e.preventDefault();
}
}
대화 상자에 포커스 가능한 요소가 있다는 것을 알고 있으면 대화 상자에 직접 초점을 맞출 필요가 없습니다. 메뉴를 작성하는 경우 첫 번째 메뉴 항목에 초점을 맞출 수 있습니다.
click: function (e) {
$(this.hash)
.toggleClass('submenu--active')
.find('a:first')
.focus();
e.preventDefault();
}
WAI-ARIA 역할 및 기타 접근성 지원
이 답변은 희망이 기능에 대한 접근 키보드와 마우스 지원의 기초를 다루고 있지만, 이미 꽤 상당한 규모의 나는이 모든 논의를 피하기 위해거야 WAI-ARIA 역할과 특성을 그러나 나는 매우 구현 세부 사항에 대한 사양을 참조하는 것이 좋습니다 그들이 어떤 역할을 사용해야하는지 그리고 다른 적절한 속성에 대해
답변
여기에있는 다른 솔루션은 저에게 효과적이지 않으므로 사용해야했습니다.
if(!$(event.target).is('#foo'))
{
// hide menu
}
답변
메뉴를 열 때 클릭 이벤트를 본문에 첨부한다는 점을 제외하고는 Eran의 예제와 비슷하게 작동하는 응용 프로그램이 있습니다 …
$('#menucontainer').click(function(event) {
$('html').one('click',function() {
// Hide the menus
});
event.stopPropagation();
});
답변
연구 후 3 가지 작동 솔루션을 찾았습니다 (참조를 위해 페이지 링크를 잊었습니다)
첫 번째 해결책
<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>
답변
$("#menuscontainer").click(function() {
$(this).focus();
});
$("#menuscontainer").blur(function(){
$(this).hide();
});
나를 위해 잘 작동합니다.