야놀자와 비슷하게 시도를 치면 구체적인 지역이 나와 그것을 클릭하면
해당 시도별 지역의 내용을 얻을 수 있게 만드는 것
기존에 MUI를 이용해서 해당 모달과 버튼등을 쉽게 사용하려고 시도 했지만
MUI가 갖고있는 특성이 서로 충돌이 나면서 내가 의도한 결과의
레이아웃이 안짜졌다. 오히려 더 복잡해졌다.
그냥 처음부터 만들자는 생각에 MUI를 사용하지 않고 직접 modal창과 전반적인 틀을 다시 짰다.
Grid를 통해 짜고 Grid Container는 display flex로 중앙에 위치시켜
모바일 화면에서도 중앙에 배치되도록 만들었다.
<html lang="ko"><head>
<meta charset="UTF-8">
<title>Modal</title>
<style>
.modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
background-color: rgba(0, 0, 0, 0.4);
}
.modal.show {
display: block;
}
.modal_body {
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 600px;
padding: 40px;
text-align: center;
background-color: rgb(255, 255, 255);
border-radius: 10px;
box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15);
transform: translateX(-50%) translateY(-50%);
}
</style>
</head>
<body cz-shortcut-listen="true" style="overflow: auto;">
<div class="modal">
<div class="modal_body">Modal</div>
</div>
<button class="btn-open-popup">Modal 띄우기</button>
</div>
<script>
const body = document.querySelector('body');
const modal = document.querySelector('.modal');
const btnOpenPopup = document.querySelector('.btn-open-popup');
btnOpenPopup.addEventListener('click', () => {
modal.classList.toggle('show');
if (modal.classList.contains('show')) {
body.style.overflow = 'hidden';
}
});
modal.addEventListener('click', (event) => {
if (event.target === modal) {
modal.classList.toggle('show');
if (!modal.classList.contains('show')) {
body.style.overflow = 'auto';
}
}
});
</script>
</body></html>
해당블로그를 참고하여 이를 응용하기로 했다.
import styled from "styled-components";
import { useState } from "react";
const CustomModal = styled.div`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
background-color: rgba(0, 0, 0, 0.4);
`;
const CustomModalBody = styled.div`
position: absolute;
top: 50%;
left: 50%;
width: 300px;
padding: 40px;
text-align: center;
background-color: rgb(255, 255, 255);
border-radius: 10px;
box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15);
transform: translateX(-50%) translateY(-50%);
`;
const ModalGridArea = styled.div`
display: grid;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(3, 1fr);
justify-content: center;
align-items: center;
justify-items: center;
align-items: center;
`;
const ModalGridAreaItem = styled.button`
background-color: #fd9f28;
width: 100px;
height: 50px;
border-radius: 10px;
text-align: center;
margin: 10px;
display: table-cell;
color: white;
`;
const GridGroup = styled.div`
display: flex;
justify-content: center;
align-items: center;
`;
const GridArea = styled.div`
width: 300px;
border: 4px solid;
display: grid;
grid-template-rows: repeat(2, 1fr);
grid-template-columns: repeat(2, 1fr);
justify-content: center;
align-items: center;
justify-items: center;
align-items: center;
`;
const GridAreaItem = styled.button`
background-color: #fd9f28;
width: 100px;
height: 50px;
border-radius: 10px;
text-align: center;
margin: 10px;
display: table-cell;
color: white;
`;
const Location = () => {
const areaArr = Object.keys(area);
const [isModalOpen, setIsModalOpen] = useState(false);
const [mainArea, setMainArea] = useState([]);
const [subArea, setSubArea] = useState([]);
const clickHandler = (mainArea) => {
setSubArea(area[mainArea]);
setMainArea(mainArea);
setIsModalOpen(true);
};
const clickModalHandler = () => {
setIsModalOpen(false);
};
const clickModalBodyHandler = (subArea) => {
setIsModalOpen(false);
// modal 클릭시 필요한 ~시 ~구 확인 가능
console.log(`${mainArea} ${subArea}`); //서울시 강남구
};
if (isModalOpen)
return (
<CustomModal
className="modal"
onClick={(e) => {
clickModalHandler(e);
}}
>
<CustomModalBody>
<ModalGridArea>
{subArea.map((t, i) => (
<ModalGridAreaItem
key={i}
onClick={(e) => {
clickModalBodyHandler(e.target.textContent);
}}
>
<p style={{ verticalAlign: "center" }}>{t}</p>
</ModalGridAreaItem>
))}
</ModalGridArea>
</CustomModalBody>
</CustomModal>
);
return (
<>
<GridGroup>
<GridArea>
{areaArr.map((t, i) => (
<GridAreaItem
key={i}
onClick={(e) => {
clickHandler(e.target.textContent);
}}
>
<p style={{ verticalAlign: "center" }}>{t}</p>
</GridAreaItem>
))}
</GridArea>
</GridGroup>
</>
);
};
export default Location;
isModalOpen
을 통해 모달창의 진행 여부를 판단하고
모달의 item을 누르거나 모달 밖을 클릭하면 모달이 사라지는 기능을 구현했다.
const area = {
서울특별시: [
"강남구",
"강동구",
"강북구",
"강서구",
"관악구",
"광진구",
"구로구",
"금천구",
"노원구",
"도봉구",
"동대문구",
"동작구",
"마포구",
"서대문구",
"서초구",
"성동구",
"성북구",
"송파구",
"양천구",
"영등포구",
"용산구",
"은평구",
"종로구",
"중구",
"중랑구",
],
인천광역시: [
"계양구",
"남구",
"남동구",
"동구",
"부평구",
"서구",
"연수구",
"중구",
"강화군",
"옹진군",
],
대전광역시: ["대덕구", "동구", "서구", "유성구", "중구"],
....
],
제주도: ["서귀포시", "제주시", "남제주군", "북제주군"],
};
해당 데이터는 예시로 이와같다.
시도별 선택지를 중앙정렬된 상태로 확인할 수 있다.
가장 도시가 많은 경기도를 클릭시 이와같은 레이아웃이 나타난다.
해당 모달창이 빠져나오고 콘솔로 그때의 시/도와 도시를 확인할 수 있다.
text의 세로 정렬을 시도하려하니 처음에 제대로 작동하지 않았다.
그 이유는vertical-align
은inline
에서만 동작하기때문에
div로 묶인 text들이 제대로 동작하지않았다.
이를 p태그로 묶고 처리하니 정상 작동되었다.
MUI와 같은 라이브러리도 좋지만 기본적으로 스스로 만들줄 아는 습관을 들여야 좀 더 복잡한 컴포넌트를 스스로 처리할 수 있는 것을 느꼈다.