유데미에서 Brad Traversy의 20 Web Projects With Vanilla JavaScript
를 하나씩 직접 코딩해보면서 정리하기 위한 글이다.
데모 페이지
Movie Seat Booking (vanillawebprojects.com)
코드 링크
github.com/rshak8912/20-Web-Projects
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<title>Movie Seat Booking</title>
</head>
<body>
<div class="movie-container">
<label>Pick a movie:</label>
<select id="movie">
<option value="10">어벤져스: 엔드게임($10)</option>
<option value="12">조커($12)</option>
<option value="8">토이스토리4($8)</option>
<option value="9">라이언킹($9)</option>
</select>
</div>
<ul class="showcase">
<li>
<div class="seat"></div>
<small>N/A</small>
</li>
<li>
<div class="seat selected">
</div>
<small>Selected</small>
</li>
<li>
<div class="seat occupied"></div>
<small>Occupied</small>
</li>
</ul>
<div class="container">
<div class="screen"></div>
<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"></div>
<div class="seat"></div>
</div>
<div class="row">
<div class="seat"></div>
<div class="seat"></div>
<div class="seat occupied"></div>
<div class="seat occupied"></div>
<div class="seat"></div>
<div class="seat"></div>
<div class="seat"></div>
<div class="seat"></div>
</div>
<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>
<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"></div>
<div class="seat"></div>
</div>
<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"></div>
<div class="seat"></div>
</div>
<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 occupied"></div>
<div class="seat occupied"></div>
<div class="seat occupied"></div>
</div>
</div>
<p class="text">You have selected <span id="count">0</span> seats for a price of
$<span id="total">0</span></p>
<script src="script.js"></script>
</body>
</html>
style.css
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
* {
box-sizing: border-box;
}
body {
background-color: #242333;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
font-family: 'Lato', sans-serif;
margin: 0;
}
.movie-container {
margin: 20px 0;
}
.movie-container select {
background-color: #ffffff;
border: 0;
border-radius: 5px;
font-size: 14px;
margin-left: 10px;
padding: 5px 15px 5px 15px;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
}
.container {
perspective: 700px;
margin-bottom: 30px;
}
.seat {
background-color: #444451;
height: 12px;
width: 15px;
margin: 3px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.seat.selected {
background-color: #6feaf6;
}
.seat.occupied {
background-color: #ffffff;
}
.seat:nth-of-type(2) {
margin-right:18px;
}
.seat:nth-last-of-type(2) {
margin-left:18px;
}
.seat:not(.occupied):hover {
cursor: pointer;
transform: scale(1.2);
}
.showcase .seat:not(.occupied):hover {
cursor: default;
transform: scale(1);
}
.showcase {
background: rgba(0, 0, 0, 0.1);
padding: 5px 10px;
border-radius: 5px;
color: #777777;
list-style-type: none;
display: flex;
justify-content: space-between;
}
.showcase li {
display: flex;
align-items: center;
justify-content: center;
margin: 0 10px;
}
.row {
display: flex;
}
.screen {
background-color: #ffffff;
height: 70px;
width: 100%;
margin: 15px 0;
transform: rotateX(-45deg);
box-shadow: 0 3px 10px rgba(255, 255, 255, 0.7);
}
p.text {
margin: 5px 0;
}
p.text span {
color:#6feaf6;
}
script.js
const container = document.querySelector('.container');
const seats = document.querySelectorAll('.row .seat:not(.occupied)');
const count = document.getElementById('count');
const total = document.getElementById('total');
const movieSelect = document.getElementById('movie');
populateUI();
let ticketPrice = +movieSelect.value; // +붙이면 타입:number
// const ticketPrice = movieSelect.value 타입:string
function setMovieData(movieIndex, moviePrice) {
localStorage.setItem('selectedMovieIndex', movieIndex);
localStorage.setItem('selectedMoviePrice', moviePrice);
}
function updateSelectedCount() {
const selectedSeats = document.querySelectorAll('.row .seat.selected');
const seatsIndex = [...selectedSeats].map(seat => [...seats].indexOf(seat));
localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex));
const selectedSeatsCount = selectedSeats.length;
count.innerText = selectedSeatsCount;
total.innerText = selectedSeatsCount * ticketPrice;
setMovieData(movieSelect.selectedIndex, movieSelect.value);
}
// get data from localstorage and popular UI
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');
}
});
}
const selectedMovieIndex = localStorage.getItem('selectedMovieIndex');
if (selectedMovieIndex !== null) {
movieSelect.selectedIndex = selectedMovieIndex;
}
}
// Movie select event
movieSelect.addEventListener('change', e => {
ticketPrice = +e.target.value;
updateSelectedCount();
})
// Seat click event
container.addEventListener('click', e => {
if (e.target.classList.contains('seat') &&
!e.target.classList.contains('occupied')) {
e.target.classList.toggle('selected');
updateSelectedCount();
}
});
// Initial count and total set
updateSelectedCount();
강의를 통해 배운점(생각 정리)
- box-sizing: border-box 속성 : box-sizing은 박스의 크기를 화면에 표시하는 방식을 변경하는 속성으로 테두리가 있는 경우에는 테두리의 두께로 인해서 원하는 크기를 찾기가 어렵지만 box-sizing 속성을 border-box로 지정하면 테두리를 포함한 크기를 지정할 수 있기 때문에 예측하기가 더 쉽다.
- align-items 속성: flex element의 수직 방향 정렬 방식을 설정한다. 이 속성은 한 줄만을 가지는 flex 박스에서는 효과가 없으며, 두 줄 이상을 가지는 flex 박스에서만 효과가 있다.
- justify-content 속성: flex element의 수평 방향 정렬 방식을 설정한다.
- appearance 속성: 운영체제 및 브라우저에 기본적으로 설정되어 있는 테마를 기반으로 요소를 표현한다. 네이티브로 지원되는 모양들을 해제하거나 추가할때 이 속성을 이용할 수 있다. 그래서 appearance 속성을 사용한 위의 css 코드에서
-moz-appearance: none; /* Firefox */
-webkit-appearance: none; /* Safari and Chrome */ 을 지원하기 위한 것이라고 볼 수 있겠다.
- css의 not 선택자 사용법을 익힐 수 있었다. Element:not(selector)
example) .seat:not(.occupied)
- parse 메소드는 string 객체를 json 객체로 변환. (string -> json)
- stringify 메소드는 json 객체를 String 객체로 변환. (json -> string)
'HTML&CSS&Javascript' 카테고리의 다른 글
[Udemy]20 Web Projects With Vanilla JavaScript -Project#5 (0) | 2020.12.10 |
---|---|
[Udemy]20 Web Projects With Vanilla JavaScript -Project#4 (0) | 2020.12.09 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#3 (0) | 2020.12.08 |
[Udemy]20 Web Projects With Vanilla JavaScript -Project#1 (0) | 2020.12.07 |
Hoisting(호이스팅) (0) | 2020.12.02 |