인터넷 강의를 보면서 영화관 자리 선택 페이지를 만들어보았습니다. 좌석을 선택하면 데이터가 저장되는 기능 위주로 초점이 맞추어진 강의였기 때문에 결과물이 마음에 차지 않아 몇 가지 기능을 추가하고 디자인을 개선했습니다. 영화를 선택하면 왼쪽 포스터가 바뀌고, 좌석을 선택할 수 있게 됩니다. 이미 예약된 좌석은 회색으로, 예약 가능한 좌석은 노란색으로 표현했으며, 선택한 좌석은 눈에 가장 잘 들어오는 빨간색 계열로 정했습니다. 선택한 좌석은 실시간으로 로컬스토리지에 저장되어 나중에 활용할 수 있도록 합니다.
영화 예매창은 반응형으로 만들되 브라우저의 가로길이에 민감하게 반응할 필요는 없다고 생각했습니다. 그래서 간단히 포스터를 보여주었다가 삭제하는 정도로 구현해보았습니다.
@media screen and (max-width: 980px) {
.ultimate-container {
width: 500px;
}
.visual-section {
display: none;
}
}
localStorage.setItem()
으로 데이터를 저장해줍니다. movieIndex
와 moviePrice
의 경우 애초에 string
형태기 때문에 JSON.stringify()
과정을 생략하였고, seatsIndex
는 배열이기 때문에 stringify
해주었습니다. 좌석을 클릭하면 각 정보가 로컬스토리지에 저장됩니다.
function setMovieData(movieIndex, moviePrice) {
localStorage.setItem('selectedMovieIndex', movieIndex)
localStorage.setItem('selectedMoviePrice', moviePrice)
}
function updateSelectedCount() {
const selectedSeats = document.querySelectorAll('.row .seat.selected')
const selectedSeatsCount = selectedSeats.length
const seatsIndex = [...selectedSeats].map((seat) => [...seats].indexOf(seat))
localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex))
}
movieSelect.addEventListener('change', (e) => {
ticketPrice = +e.target.value
setMovieData(e.target.selectedIndex, e.target.value)
updateSelectedCount()
})
영화를 선택하면, 선택한 요소의 index
값을 가지고 영화와 일치하는 포스터 클래스를 추가해보았습니다. 썩 마음에 드는 코드는 아니지만 개인적으로 e.target.selectedIndex
나 classList
등 DOM 공부를 할 수 있었습니다.
.poster1 {
background-image: url(https://images-na.ssl-images-amazon.com/images/I/91IlgV6rVtL._AC_SY741_.jpg);
background-size: cover;
}
.poster2 {
background-image: url(https://xl.movieposterdb.com/11_07/1992/103639/xl_103639_2c39a065.jpg);
background-size: cover;
}
.poster3 {
background-image: url(https://wdwnt.com/wp-content/uploads/2018/11/DtGT1ZmW0AASOkw1.jpg);
background-size: cover;
}
.poster4 {
background-image: url(https://images-na.ssl-images-amazon.com/images/I/81S36TZzg9L._AC_SL1500_.jpg);
background-size: cover;
}
const visualSection = document.querySelector('.visual-section')
movieSelect.addEventListener('change', (e) => {
ticketPrice = +e.target.value
setMovieData(e.target.selectedIndex, e.target.value)
visualSection.classList.remove(visualSection.classList[1])
visualSection.classList.add(`poster${e.target.selectedIndex}`)
updateSelectedCount()
})
새로고침을 해도 정보가 남아있도록 만들었습니다. 로컬스토리지에 저장된 데이터를 parse
해서 결과물이 유효한 값이면 forEach()
메서드로 하나씩 selected
클래스를 추가해, 선택한 좌석은 빨간색으로 여전히 표기될 수 있도록 했습니다.
function populateUI() {
const selectedSeats = JSON.parse(localStorage.getItem('selectedSeats'))
if (selectedSeats !== null && selectedSeats.length > 0) {
seats.forEach((seat, index) => {
if (selectedSeats.indexOf(index) > -1) {
seat.classList.add('selected')
}
})
}
}
populateUI()
선택한 좌석에 대한 데이터를 가지고 저장하고 출력하는 데 집중하다 보니, 영화를 고르지 않은 상태에서도 좌석를 선택할 수 있는 등 디테일이 부족했습니다. option value
가 0
이 아닌 경우에만 클래스를 toggle
할 수 있도록 기능을 추가했습니다.
<div class="movie-container">
<label>Pick a movie</label>
<select id="movie">
<option value="0" selected >Select a movie</option>
<option value="10000">Frozen 2 (₩10,000)</option>
<option value="12000">Aladdin (₩12,000)</option>
<option value="8000">Toy Story4 (₩8,000)</option>
<option value="9000">The Lion King (₩9,000)</option>
</select>
</div>
const movieSelect = document.getElementById('movie')
container.addEventListener('click', (e) => {
if ( movieSelect.value > 0 && e.target.classList.contains('seat') && !e.target.classList.contains('occupied')
) {
e.target.classList.toggle('selected')
updateSelectedCount()
}
})
총 영화값을 천 자리 단위로 끊어서 출력하기 위해 구글링해서 아래와 같은 함수를 찾아 적용했습니다.
const count = document.getElementById('count')
const total = document.getElementById('total')
function numberWithCommas(price) {
return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
count.innerText = selectedSeatsCount
total.innerText = numberWithCommas(selectedSeatsCount * ticketPrice)
혹시 전체 코드좀 알수 있을까요