Html에 있는 select태그, option태그로는 커스텀에 한계가 있어 직접 만들어보는 방법을 알아보았다.
Html
기본 구조는 select태그 역할을 하는 선택된 값과 option들 값들을 분리하여 클래스 명이 selectBox인 div 태그 안에 배치 한다.
<section>
<!-- 1번째 select -->
<div class="selectBox">
<div class="selected">
<div class="selected-value">drink</div>
<div class="arrow">
<img src="/public/image/downArrow.svg" alt="arrow" />
</div>
</div>
<ul class="optionList">
<li class="option">coffee</li>
<li class="option">water</li>
<li class="option">latte</li>
<li class="option">jucie</li>
</ul>
</div>
<!-- 2번째 select -->
<div class="selectBox">
<div class="selected">
<div class="selected-value">food</div>
<div class="arrow">
<img src="/public/image/downArrow.svg" alt="arrow" />
</div>
</div>
<ul class="optionList">
<li class="option">pizza</li>
<li class="option">rice</li>
<li class="option">burger</li>
<li class="option">bread</li>
</ul>
</div>
</section>
Css
원하는 모양으로 커스텀을 한다.
- 아래 코드는 option들이 클릭 시 나타날 때 스르륵 나타났으면 해서 optionList (= ul) 기본으로 max-height: 0; overflow: hidden; 값을 주고 selectBox에 active 클래스 명이 추가되면 optionList (= ul) 에 max-height: 500px; 값을 주었다.
section {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
margin-top: 20px;
}
.selectBox {
cursor: pointer;
margin-right: 20px;
}
.selected {
width: 150px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 5px;
border-radius: 4px;
border: 2px solid rgb(0, 180, 45);
}
.select .selected .selected-value {
max-width: 90px;
}
.arrow {
display: flex;
align-items: center;
justify-content: center;
width: 10px;
height: 10px;
}
.arrow img {
width: 100%;
}
.selectBox .optionList {
position: absolute;
margin-top: 4px;
width: 150px;
border-radius: 4px;
background: #fff;
cursor: pointer;
max-height: 0;
overflow: hidden;
transition: 0.5s ease-in;
}
.selectBox .option {
border-left: 2px solid rgb(0, 180, 45);
border-right: 2px solid rgb(0, 180, 45);
}
.selectBox .option:first-of-type {
border-top: 2px solid rgb(0, 180, 45);
}
.selectBox .option:last-of-type {
border-bottom: 2px solid rgb(0, 180, 45);
}
.selectBox.active .optionList {
max-height: 500px;
}
.selectBox.active .arrow {
transform: scaleY(-1);
}
.option {
padding: 8px 5px;
}
.option:hover {
background: rgb(180, 211, 188);
}
Javascript
Javascript을 통해 select 기능을 만들었다.
- active 클래스 명을 추가하거나 삭제하는 토글 기능을 toggleSelectBox() 함수를 통해 구현하고 selectOption() 함수를 통해 선택된 한 option 값으로 변경되게 했다.
- selectBox 가 여러개일 경우를 대비해 forEach()문을 통해 각 selectBox 에 클릭 이벤트를 추가하여 toggleSelectBox(), selectOption() 함수가 실행되게 했다.
- 마지막으로 문서 전체에 클릭 이벤트 리스너 추가하여 selectBox 이외의 부분을 클릭했을 때, 옵션을 클릭했을 때 모든 selectBox에서 'active' 클래스 제거했다.
<script>
// 모든 셀렉션 박스 엘리먼트 선택
const selectBoxElements = document.querySelectorAll(".selectBox");
//.optionList
function toggleSelectBox(selectBox) {
selectBox.classList.toggle("active");
}
// 옵션 선택 함수 / closest() - 가장 가까운 조상
function selectOption(optionElement) {
const selectBox = optionElement.closest(".selectBox");
const selectedElement = selectBox.querySelector(".selected-value");
selectedElement.textContent = optionElement.textContent;
}
// 각 셀렉션 박스에 클릭 이벤트 리스너 추가
selectBoxElements.forEach((selectBoxElement) => {
selectBoxElement.addEventListener("click", function (e) {
const targetElement = e.target;
const isOptionElement = targetElement.classList.contains("option");
if (isOptionElement) {
selectOption(targetElement);
}
toggleSelectBox(selectBoxElement);
});
});
// 문서 전체에 클릭 이벤트 리스너 추가
// 모든 셀렉션 박스 이외의 부분을 클릭했을 때,
// 모든 셀렉션 박스에서 'active' 클래스를 제거하여 옵션 목록을 숨긴다.
document.addEventListener("click", function (e) {
const targetElement = e.target;
const isSelect =
targetElement.classList.contains("selectBox") ||
targetElement.closest(".selectBox");
if (isSelect) {
return;
}
// 모든 셀렉션 박스에서 'active' 클래스 제거
const allSelectBoxElements = document.querySelectorAll(".selectBox");
allSelectBoxElements.forEach((boxElement) => {
boxElement.classList.remove("active");
});
});
</script>
전체코드
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
section {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
margin-top: 20px;
}
.selectBox {
cursor: pointer;
margin-right: 20px;
}
.selected {
width: 150px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 5px;
border-radius: 4px;
border: 2px solid rgb(0, 180, 45);
}
.select .selected .selected-value {
max-width: 90px;
}
.arrow {
display: flex;
align-items: center;
justify-content: center;
width: 10px;
height: 10px;
}
.arrow img {
width: 100%;
}
.selectBox .optionList {
position: absolute;
margin-top: 4px;
width: 150px;
border-radius: 4px;
background: #fff;
cursor: pointer;
max-height: 0;
overflow: hidden;
transition: 0.5s ease-in;
}
.selectBox .option {
border-left: 2px solid rgb(0, 180, 45);
border-right: 2px solid rgb(0, 180, 45);
}
.selectBox .option:first-of-type {
border-top: 2px solid rgb(0, 180, 45);
}
.selectBox .option:last-of-type {
border-bottom: 2px solid rgb(0, 180, 45);
}
.selectBox.active .optionList {
max-height: 500px;
}
.selectBox.active .arrow {
transform: scaleY(-1);
}
.option {
padding: 8px 5px;
}
.option:hover {
background: rgb(180, 211, 188);
}
</style>
</head>
<body>
<section>
<div class="selectBox">
<div class="selected">
<div class="selected-value">drink</div>
<div class="arrow">
<img src="/public/image/downArrow.svg" alt="arrow" />
</div>
</div>
<ul class="optionList">
<li class="option">coffee</li>
<li class="option">water</li>
<li class="option">latte</li>
<li class="option">jucie</li>
</ul>
</div>
<div class="selectBox">
<div class="selected">
<div class="selected-value">food</div>
<div class="arrow">
<img src="/public/image/downArrow.svg" alt="arrow" />
</div>
</div>
<ul class="optionList">
<li class="option">pizza</li>
<li class="option">rice</li>
<li class="option">burger</li>
<li class="option">bread</li>
</ul>
</div>
</section>
<script>
// 모든 셀렉션 박스 엘리먼트 선택
const selectBoxElements = document.querySelectorAll(".selectBox");
//.optionList
function toggleSelectBox(selectBox) {
selectBox.classList.toggle("active");
}
// 옵션 선택 함수 / closest() - 가장 가까운 조상
function selectOption(optionElement) {
const selectBox = optionElement.closest(".selectBox");
const selectedElement = selectBox.querySelector(".selected-value");
selectedElement.textContent = optionElement.textContent;
}
// 각 셀렉션 박스에 클릭 이벤트 리스너 추가
selectBoxElements.forEach((selectBoxElement) => {
selectBoxElement.addEventListener("click", function (e) {
const targetElement = e.target;
const isOptionElement = targetElement.classList.contains("option");
if (isOptionElement) {
selectOption(targetElement);
}
toggleSelectBox(selectBoxElement);
});
});
// 문서 전체에 클릭 이벤트 리스너 추가
// 모든 셀렉션 박스 이외의 부분을 클릭했을 때,
// 모든 셀렉션 박스에서 'active' 클래스를 제거하여 옵션 목록을 숨긴다.
document.addEventListener("click", function (e) {
const targetElement = e.target;
const isSelect =
targetElement.classList.contains("selectBox") ||
targetElement.closest(".selectBox");
if (isSelect) {
return;
}
// 모든 셀렉션 박스에서 'active' 클래스 제거
const allSelectBoxElements = document.querySelectorAll(".selectBox");
allSelectBoxElements.forEach((boxElement) => {
boxElement.classList.remove("active");
});
});
</script>
</body>
</html>
결과
'Javascript' 카테고리의 다른 글
input checkbox 하나만 선택 (0) | 2024.08.26 |
---|---|
AOS 라이브러리 (0) | 2024.08.26 |
map(), filter(), find() (0) | 2024.08.25 |
특정 위치에 해당하는 문자 찾기 (0) | 2024.08.25 |
특정 문자 위치 찾기 - indexOf 함수 (0) | 2024.08.25 |