요즘 내가 진행하고 있는 프로젝트에 여러 개의 조건을 받아 정보를 필터링하는 기능이 들어있다.
조건을 받기 위한 dropdown을 만들었는데 한 가지 문제점이 보였다.
dropdown이 중복으로 열리면 사용자가 보기에 불편할 것이다.
그래서 1개의 dropdown이 열려있는 상태에서 다른 dropdown을 클릭하면 이미 열려있는 것은 닫히는 기능을 코드로 짜보았다.
<div class="filter-group">
<div class="filter">
<button class="filter-toggle">종류</button>
<ul class="filter-menu">
<li class="filter-option">한식</li>
<li class="filter-option">중식</li>
<li class="filter-option">일식</li>
</ul>
</div>
<div class="filter">
<button class="filter-toggle">인원</button>
<ul class="filter-menu">
<li class="filter-option">1명</li>
<li class="filter-option">2명</li>
<li class="filter-option">3명</li>
</ul>
</div>
<div class="filter">
<button class="filter-toggle">기타</button>
<ul class="filter-menu">
<li class="filter-option">비건</li>
<li class="filter-option">스타쉐프</li>
<li class="filter-option">방송출연</li>
</ul>
</div>
</div>
3개의 dropdown form을 만들어줍니다.
filter-group
: filter
들의 집합
filter
: 하나의 dropdown 기능을 구현하는 form
filter-toggle
: 클릭 시 filter-menu
toggle
filter-menu
: filter-option
이라는 선택사항을 갖고있는 dropdown
* {
padding: 0;
margin: 0;
}
.filter-group {
display: flex;
justify-content: start;
align-items: start;
margin: 20px;
}
.filter {
position: relative; // ☆
margin-right: 8px;
}
.filter-toggle {
display: flex;
justify-content: center;
align-items: center;
padding: 4px 16px;
background-color: #eeeeee;
border-radius: 30px;
border: none;
}
.filter-toggle:hover {
background-color: pink;
}
.filter-menu {
visibility: hidden; // ★
position: absolute; // ☆
left: 0; // ☆
top: 40px; // ☆
padding: 8px 0;
width: 240px;
max-height: 400px;
border-radius: 8px;
background-color: #fff;
opacity: 0; // ★
overflow-y: auto;
transform: translate3d(0, -20px, 0); // ★
transition: all 200ms ease-in-out; // ★
box-shadow: 0 4px 20px rgba(63, 65, 80, 0.3);
list-style-type: none;
}
.filter.is-open .filter-menu {
visibility: visible; // ★
transform: translate3d(0, 0, 0); // ★
opacity: 1; // ★
}
.filter-option {
padding: 16px 24px;
}
여기서 가장 중요한 부분은 ★로 주석된 속성들이다.
filter-menu
가 보이지 않도록 처리한 후,
filter
에 is-open
이 추가되었을 때 filter-menu
를 보이게 만드는 것이다.
transition
속성을 사용해 부드럽게 toggling 할 수 있게 된다.
☆로 주석된 부분은 filter-menu
를 적절하게 위치시킨 것이다.
나머지는 원하는 스타일에 맞게 바꿀 수 있다.
// 1번째
const filterButtonList = document.querySelectorAll(".filter-toggle");
// 3번째
function toggleFilterMenu() {
const filter = this.parentNode;
const filterOpened = document.querySelector(".filter.is-open");
// 3-1
if (filterOpened) {
console.log(1); // 1번 동작 확인
filterOpened.classList.remove("is-open");
}
// 3-2
if (filter != filterOpened) {
console.log(2); // 2번 동작 확인
filter.classList.add("is-open");
}
}
// 2번째
filterButtonList.forEach(function (button) {
button.addEventListener("click", toggleFilterMenu);
});
filterButtonList
에 filter-toggle
을 미리 선언한다.
filterButtonList
를 클릭하면 toggleFilterMenu
함수를 실행시킨다.
foreach는 배열을 하나씩 실행하는 것이다.
filterButtonList
가querySelectorAll
를 사용해 선언되었으므로, 이것은 Array(배열)이다.
filter
에 this(=filterButtonList =filter-toggle)
의 부모 요소를 선언한다.filter
에 is-open
을 toggle 할 예정 3-1. 이미 is-open
상태인 filter
가 있는 경우, is-open
을 삭제한다.
3-2. filter
가 is-open
상태가 아닌 경우, is-open
을 추가한다.
X➡클릭 | 동일한 버튼 클릭 | 다른 버튼 클릭 |
---|---|---|
2번 동작 | 1번동작 | 1번동작➡2번동작 |
이 기능은 dropdown 뿐만 아니라 radio-box와 같이 여러 선택지 중 하나만 골라야 하는 경우에도 쓰일 수 있다.