본문 바로가기

자바스크립트/DOM 예제

다른 곳을 클릭 했을 때 드롭다운 메뉴를 사라지게 하는 방법

버튼을 클릭 했을 때 드롭다운 메뉴가 나타나게 하는 것까지는 했다고 치자.

여기서 메뉴를 클릭하지 않고 다른 곳을 클릭 했을 때 드롭다운 메뉴가 사라지는 방법에 대해 다루겠다.

알고 보면 별 것 아닌데 모르면 어렵게 구현해야 한다.

 

1. HTML

<div class="button-container">
  <button class="button">클릭</button>
  <div class="dropdown">
    <div class="dropdown-item">서울</div>
    <div class="dropdown-item">대전</div>
    <div class="dropdown-item">대구</div>
    <div class="dropdown-item">부산</div>
  </div>
</div>

 

반드시 button 엘리먼트를 써서 이벤트를 구현해야 한다.

input류의 엘리먼트만 blur 이벤트가 적용되기 때문이다.

(일반 엘리먼트에 blur 이벤트를 넣고 싶다면 tabindex 속성을 활용하자.)

https://developer.mozilla.org/ko/docs/Web/HTML/Global_attributes/tabindex

 

blur 이벤트는 선택이 해제됐을 때 발생하는 이벤트다.

버튼을 클릭했을 때 버튼을 선택한 상태가 되고 (focus)

버튼이 아닌 다른 곳을 클릭하면 선택 상태가 해제되어 button에 blur 이벤트가 발생한다.

 

2. Javascript

const button = document.querySelector('.button');

button.addEventListener('click', () => {
  const dropdown = document.querySelector('.dropdown');
  dropdown.style.display = 'block';
});

button.addEventListener('blur', () => {
  const dropdown = document.querySelector('.dropdown');
  dropdown.style.display = '';
});

 

button을 클릭했을 때 dropdown의 display를 보여주고(block)

button 선택이 해제될 때(blur) display를 원상태로 돌린다.

CSS에서 display의 값을 none으로 했기 때문에 빈 string을 넣어주면 원래 상태로 돌아간다.

 

다만 다른 곳을 클릭할 때 뿐만 아니라

드롭다운 내부의 아이템을 클릭하는 경우에도 blur 이벤트가 발생하기 때문에

클릭시 blur 이벤트가 먼저 발생하고 드롭다운이 사라져 아이템 클릭 이벤트가 먹히지 않을 수 있으니

아래처럼 setTimeout을 추가해서 드롭다운이 사라지는 시간을 살짝 지연시키든지 하는 작업이 더 필요하다.

 

button.addEventListener('blur', () => {
  const dropdown = document.querySelector('.dropdown');
  
  // 0.2초 뒤에 실행
  setTimeout(() => {
    dropdown.style.display = '';
  }, 200);
});

 

더 간단한 방법으로 드롭다운의 아이템 클릭시 발생하는 이벤트에 click 이벤트 대신 mousedown 이벤트를 쓰면

blur 이벤트 이전에 호출되기 때문에 위 문제를 쉽게 해결할 수 있다.

https://stackoverflow.com/questions/12092261/prevent-firing-the-blur-event-if-any-one-of-its-children-receives-focus

 

3. CSS

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  height: 100vh;
}

.button-container {
  position: relative;
}

.button {
  display: flex;
  align-items: center;
  background: white;
  border: 1px solid grey;
  padding: 10px;
  font-size: 1rem;
  cursor: pointer;
  outline: none;
}

.dropdown {
  display: none;
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  width: 100px;
  border: 1px solid grey;
}

.dropdown-item {
  text-align: center;
  padding: 10px;
  cursor: pointer;
}

.dropdown-item:hover {
  background: whitesmoke;
}

 

body는 가운데 정렬을 위한 설정이고

부모인 button-container의 position을 relative로 하고 자식인 dropdown을 absolute로 해야

부모 위치를 기준으로 dropdown의 위치를 조절 할 수 있다.

 

여기서는 top에 100%를 줘서 부모의 height 만큼 내려오게 하여

button 바로 밑에 dropdown이 붙도록 했다.

left에 50%를 주면 왼쪽 모서리가 부모의 중간 지점에 오고

transform에 translateX(-50%)를 주면 자신의 width 반절만큼 왼쪽으로 움직인다.

결과적으로 아래처럼 부모를 기준으로 가운데 정렬이 된다.