برنامه رزرو صندلی سینما با جاوا اسکریپت

Movie Seat Booking with JavaScript

16 اردیبهشت 1401
Movie-Seat-Booking-with-JavaScript

در این آموزش، برنامه رزور صندلی با جاوا اسکریپت را شبیه سازی و پیاده سازی خواهیم کرد. در این برنامه صندلی ها در سطرها و ستون ها نمایش داده می شوند و با کلیک کردن روی یک صندلی خالی می توانیم آن را رزور کنیم.با دوباره کلیک کردن روی صندلی از حالت انتخاب شده خارج می شود. کاربر هم چنین صندلی هایی را که از انتخاب شده اند، نمی تواند انتخاب کند.

کاربر از بین چند فیلم یک فیلم را می تواند انتخاب کند. هر کدام از این فیلم ها قیمت های مختلفی دارند. قیمت نهایی بر پایه قیمت فیلم و تعداد صندلی های انتخاب شده تعیین و نمایش داده می شود. اگر صفحه را رفرش کنیم اطلاعات یا همان صندلی های انتخاب تغییر نخواهند کرد. این کار را با استفاده از localStorage انجام خواهیم داد.

تصویر برنامه رزور صندلی با جاوا اسکریپت در زیر آمده است:

پیش نیاز

برای ساخت برنامه رزور صندلی با جاوا اسکریپت، به آشنایی با html ،css و javascript نیاز دارید.

ساختار پروژه

برای ساخت این پروژه به فایل های index.html، style.css و script.js نیاز داریم.

فایل index.html برای تعیین ساختار برنامه است. در این فایل عناصر مختلف خود مانند تگ body و ... را تعریف می کنیم. فایل های style.css و script.js در این فایل قرار می گیرند.style.css در  تگ head و script.js در انتهای تگ body قرار می گیرد.

style.css برای استایل دهی و script.js برای پیاده سازی منطق برنامه رزور صندلی با جاوا اسکریپت به کار می رود. تک تک فایل ها را در زیر توضیح می دهیم و به نحو پیاده سازی آن ها می پردازیم.

فایل index.html

کد این فایل در زیر آمده است:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <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">Avengers: Endgame ($10)</option>
        <option value="12">Joker ($12)</option>
        <option value="8">Toy Story 4 ($8)</option>
        <option value="9">The Lion King ($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"></div>
        <div class="seat occupied"></div>
        <div class="seat occupied"></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 occupied"></div>
        <div class="seat occupied"></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 occupied"></div>
        <div class="seat occupied"></div>
        <div class="seat occupied"></div>
        <div class="seat"></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 و script.js نیز در اینجا قرار می گیرند. style.css در تگ head و script.js در انتهای تگ body قرار می گیرند.

در اینجا به چهار تگ اصلی نیاز داریم:

  1. یک تگ div با کلاس movie-container که برای نمایش نام فیلم ها و قیمت ها استفاده می شود.
  2. تگ ul با کلاس show-case برای نمایش مفهوم رنگ صندلی ها
  3. تگ div با کلاس container برای نمایش پرده نمایش و صندلی ها
  4. تگ p با کلاس text برای نمایش قیمت نهایی و تعداد صندلی های انتخاب شده

به تصویر زیر نگاه کنید تا بهتر متوجه شوید:

کد این چهار تگ اصلی را می توانید در بالا ببینید.

فایل 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: #fff;
  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: 1000px;
  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: #fff;
}

.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: #777;
  list-style-type: none;
  display: flex;
  justify-content: space-between;
}

.showcase li {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 10px;
}

.showcase li small {
  margin-left: 2px;
}

.row {
  display: flex;
}

.screen {
  background-color: #fff;
  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;

// Save selected movie index and price
function setMovieData(movieIndex, moviePrice) {
  localStorage.setItem('selectedMovieIndex', movieIndex);
  localStorage.setItem('selectedMoviePrice', moviePrice);
}

// Update total and count
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;
}

// Get data from localstorage and populate 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;
  setMovieData(e.target.selectedIndex, 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();


برای دستیابی به عناصر DOM و کار با آن ها متغیرهای زیر را تعریف می کنیم و با استفاده از متدهای ویژه DOM آن ها را وارد 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');

برای به دست آوردن قیمت فیلم متغیر ticketPrice را تعریف می کنیم:

let ticketPrice = +movieSelect.value;

عملگر + که پیش از movieSelect آمده است برای تبدیل نوع آن به یک عدد صحیح است. در ادامه برای انجام هر یک از کارها توابع ویژه آن ها را خواهیم ساخت. در تابع زیر وقتی صندلی کلیک می شود و همراه با آن یک فیلم انتخاب می شود، اطلاعات در localStorage ذخیره می شوند. نام این تابع setMoiveData است:

// Save selected movie index and price
function setMovieData(movieIndex, moviePrice) {
  localStorage.setItem('selectedMovieIndex', movieIndex);
  localStorage.setItem('selectedMoviePrice', moviePrice);
}

با توجه به تعداد صندلی ها و فیلم (هر فیلم یک قیمت دارد) انتخاب شده باید هزینه نهایی محاسبه شود و در پایین نمایش داده شود. برای انجام این کار تابع updateSelectedCount را داریم.

// Update total and count
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;
}

تابع بالا ابتدا همه صندلی های انتخاب شده یعنی صندلی هایی که دارای کلاس .selected هستند را می گیرد و سپس اندیس آن ها را به دست می آورد. این اندیس ها در localStorage ذخیره می شوند. از این اندیس ها در آینده استفاده خواهیم کرد. در آخر تعداد صندلی های انتخاب شده  و قیمت آن ها را حساب می کنیم.

اگر صفحه را رفرش کنیم صندلی های انتخاب شده و سایر اطلاعات ناپدید می شوند. برای این که این اتفاق نیفتد باید اطلاعاتی را که در  localStorage ذخیره شده اند، بازیابی کنیم و با آن ها صفحه را به روز کنیم. برای این کار از تابع populateUI استفاده می کنیم:

// Get data from localstorage and populate 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;
  }
}

در بالا همه صندلی های انتخاب شده که در اندیس آن ها در localStorage هستند را می گیریم و آن ها در متغیر selectedSeats قرار می دهیم. سپس برای هر یک از این صندلی ها کلاس selected را اضافه می کنیم. در آخر هم تعداد صندلی ها و قیمت نهایی را به روز می کنیم.

اگر از بین فیلم های موجود یکی را انتخاب کنیم رویداد change رخ  می دهد. برای رسیدگی به این رویداد از کد زیر استفاده می کنیم.

// Movie select event
movieSelect.addEventListener('change', e => {
  ticketPrice = +e.target.value;
  setMovieData(e.target.selectedIndex, e.target.value);
  updateSelectedCount();
});

وقتی که روی صندلی کلیک می شود باید آن صندلی اگر از پیش انتخاب نشده باشد باید آبی رنگ شود، یعنی کلاس selected که در فایل css آن را تعریف کرده ایم به آن نسبت داده شود. به عبارت دیگر باید رویداد کلیک را مدیریت کنیم. پس داریم:

// Seat click event
container.addEventListener('click', e => {
  if (
    e.target.classList.contains('seat') &&
    !e.target.classList.contains('occupied')
  ) {
    e.target.classList.toggle('selected');

    updateSelectedCount();
  }
});

منبع: وب سایت github

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.