프로젝트 설명
간단한 영화관 좌석 선택 기능 구현입니다. 영화관 좌석 배치표를 보여주며 선택 가능한 좌석을 클릭하면 해당 좌석을 강조해줍니다. 좌석표 아래에는 몇 개의 좌석을 선택했는지와 총 영화표 값을 보여줍니다.
기억하고싶은 내용
CSS
nth-of-type
<div class="row">
<div class="seat"></div>
<div class="seat"></div>
<div class="seat"></div>
<div class="seat"></div>
<div class="seat"></div>
<div class="seat"></div>
<div class="seat occupied"></div>
<div class="seat occupied"></div>
</div>
.seat:nth-of-type(2) {
margin-right: 18px;
}
.seat:nth-last-of-type(2) {
margin-left: 18px;
}
왼쪽, 오른쪽은 두열씩 배치됨을 보여주기 위해 사용한 css문법입니다. 좌석은 각 행에 8좌석씩 존재합니다. 양쪽 두 좌석 사이에 길이 있기 때문에 떨어트려 보여줍니다.
해당 css가 적용되지 않는다면 이렇게 좌석들이 붙어있게 됩니다.
만약 제가 이것을 예제처럼 구현한다면 flex box로 만든 후 direction을 column으로 주어서 정렬했을 것입니다. 하지만 그렇게 한다면 해당 열들을 기준으로 class이름을 새로 지정해야 하기 때문에 추후 배치를 수정하고자 한다면 추가적인 과정이 생기게 됩니다.
하지만 강의에서는 nth-of-type을 사용하여 간단하게 구현하였습니다. nty-of-type은 형제 그룹들을 기반으로 n번째 요소를 매칭하는데요, 각 row 안에 seat들이 있기 때문에 해당 각각의 row마다 동일하게 마진을 줄 수 있습니다.
:not(.class)
.seat:not(.occupied):hover {
cursor: pointer;
transform: scale(1.2);
}
seat들에 마우스가 hover되면 선택가능임을 나타내기 위해 커서모양을 변경하고 크기를 키워줍니다. 이미 예약이 완료된 좌석에는 이러한 변경을 적용하지 않기 위해서 해당 문법을 사용하였습니다.
css를 작성 할 때 다양한 css문법을 알고있지 않아서 늘 class이름에 고유성을 부여하고자 했습니다. 그렇게 된다면 당연히 유지보수가 어려워지는데요, 유용한 css문법을 익히는것도 중요하다는것을 깨달았습니다.
이벤트 위임
container 안에 좌석들이 여러개 존재합니다. 각 좌석을 클릭 할 때 마다 클릭 이벤트를 주어야 하는데 이 때 모든 seat를 가져와서 for루프를 돌며 이벤트를 할당 할 수도 있겠지만 이벤트 위임을 통해 간단하게 이벤트를 등록할 수 있습니다.
container.addEventListener('click', (e) => {
if (
e.target.classList.contains('seat') &&
!e.target.classList.contains('occupied')
) {
e.target.classList.toggle('selected');
updateSelectedCount();
}
});
이는 엘리먼트를 클릭하면 이벤트 버블링으로 인해 document에 도달할 때 까지 부모요소들의 이벤트를 실행시키기 때문에 가능합니다. 자식 요소가 아닌 부모 요소에 이벤트를 걸어두어도 자식을 클릭하면 결국 부모의 이벤트가 실행 됩니다. 따라서 한번의 이벤트 핸들러 안에서 조건식으로 이벤트를 관리하면 핸들러를 한번만 할당해주어도 됩니다.
Local Storage
해당 페이지를 새로고침 하여도 기존에 선택했던 좌석 선택 정보가 존재하도록 하기 위해 local storage에 선택된 좌석들의 index배열을 저장시킵니다.
const seatsIndex = [...selectedSeats].map((seat) => [...seats].indexOf(seat));
localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex));
UI를 로딩 할때 local storage에 저장해 둔 정보를 읽어와 나타냅니다.
const selecedSeats = JSON.parse(localStorage.getItem('selectedSeats'));
if (selecedSeats !== null && selecedSeats.length > 0) {
seats.forEach((seat, index) => {
if (selecedSeats.indexOf(index) > -1) {
seat.classList.add('selected');
}
});
}
개인적으로 추가한 기능
local storage에 기록을 해 두었기 때문에 리프레쉬가 되어도 선택된 좌석 정보가 남습니다. 따라서 한번에 모든 좌석 선택을 취소하는 기능을 따로 구현할 필요성을 느껴서 reset버튼을 구현했습니다. 클릭하면 모든 선택된 좌석들이 취소가됩니다.