# JS練習_電影院訂位頁面 製作一個電影訂位的網頁,可以透過選取的座位數以及不同的電影,呈現不同的票價。 最終畫面呈現: ![](https://i.imgur.com/pK4oigy.png) [成果網頁](https://chrislinlin.github.io/my-projects/mentor_mission/mission_22/index.html?) ## 成品功能 - 可以選擇不同電影 - 可以選擇座位 - 加總選取座位配合搭配電影的票價獲得消費總額 - 頁面重新整理時,資料保有在原始頁面 ## HTML - 用select and option做出下拉式選單,並在option後帶入代表票價的value ```htmlembedded= <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 及 li做出座位狀態表,再利用容器div給予屬性裡面包覆很多小容器代表座位。 ```htmlembedded= <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 occupied"></div> <div class="seat occupied"></div> <div class="seat"></div> <div class="seat"></div> <div class="seat"></div> </div> ``` - 利用標籤p 做出選取的座位數及票價的文字呈現,並利用span標籤讓帶入JS時可以更方便選取。 ```htmlembedded= <p class="text"> You have selected <span id="count">0</span> seats for a price of $<span id="total" >0</span > </p> ``` ## CSS 網頁整體以flex為主,只要設定致中,版面設置滿版 - `appearance` - 由於不同瀏覽器的支援不同,針對不同瀏覽器的預設樣式修正。 - `macOS`使用的`safari`需要`-webkit-appearance: none;`來防止預設的瀏覽器樣式。 ```css= .movie-container select { -moz-appearance: none; -webkit-appearance: none; appearance: none; } ``` 先設定好選擇好的座位及特定的座位的css,就算一開始html沒有在標籤內填入這些屬性也可之後JS帶入時,直接更改classname就可套用設定好的css。 ```css= .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); } ``` 電影螢幕透過css 3D透視效果及搭配本身螢幕容器設定`transform:rotate`屬性及`box-shadow`屬性做出類似電影院的效果 ```css= .container { perspective: 1000px; /*3D效果*/ margin-bottom: 30px; } .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); } ``` ## JS 1. 宣告變數,要是變數之後還會改變,就會利用`let` ```.js let ticketPrice = +$('#movie').val();//jquery沒有'.value" 只有val() let seats = $('.row .seat:not(.occupied)'); ``` 2. 用click事件呼叫callback function,且利用`toggle`屬性,將參數未有的標籤加上,有的標籤去除。 - 用click事件方式呼叫callback function - 用.target得到元素並用`toggle()` 判斷在函式中判斷參數是否含有某class。 [target小科普]() - 用if條件判斷符合,就可以在使用toggle()加入selected屬性使他變色 - 最後呼叫一次**updateSelectedCount()** 函式,讓我們每產生點擊事件一次,即可更新下方文字敘述。 ```.js= $(document).ready(function(){ $('.container').click(function(e){ if(e.target.classList.contains('seat') && !e.target.classList.contains('occupied')){ e.target.classList.toggle('selected'); //因為用toggle 會把沒有的變成有,若有的就會變沒有 updateSelectedCount(); } }); }); ``` 3. 使用者可以自由選擇座位,但已選的不能選 - 編寫步驟如下: - 把選取的座位放到arr - 用map()方法更新arr - 在return到新的arr - 利用`...`運算來將我們選取的位置傳入`[]`成為陣列`array`, - 利用`map()`這個方法處理陣列中的元素,返回我們選取的位置在陣列中的索引值(在陣列中哪個位置,從零開始,利用`indexOf()`方法)。 - 將取得的索引值存入`localStorage`,給定兩個參數(keyName, keyValue), 第一個參數作用是給定名稱,稱為`keyName`(鍵名) => 下面這個例子叫做`selectedSeats` 第二個參數作用是給定值,稱為`keyValue`(鍵值)也就是這個`keyName`對應的值。 但`keyName`和`keyValue`都必須是字串型別,所以用`JSON.stringify()`將陣列轉成字串型別。 [LocalStorage 筆記傳送門](https://hackmd.io/@chrislinlin/js_localstorage) ```.js= function updateSelectedCount(){ $(document).ready(function(){ const selectSeats = $('.row .seat.selected'); const selectedSeats = $('.row .seat.selected'); const seatsIndex = [...selectedSeats].map(function(seat){ return [...seats].indexOf(seat); }) localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex)); const selectedSeatsCount = selectSeats.length; $('#count').text(selectedSeatsCount); $('#total').text(selectedSeatsCount * ticketPrice) ; }); ``` 4. 使用者可以選擇電影,帶入不同的價格 ```.js= $('#movie').change(function(e){ ticketPrice = $(e.target).val(); setMovieData(e.target.selectedIndex, $(e.target).val()); //這個selectedIndex在哪 updateSelectedCount(); }) ``` 5. 每選一個位置,位置圖下有數量跟座位數的正比關係 ```.js= function updateSelectedCount(){ $(document).ready(function(){ const selectSeats = $('.row .seat.selected'); const selectedSeats = $('.row .seat.selected'); const seatsIndex = [...selectedSeats].map(function(seat){ return [...seats].indexOf(seat); }) localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex)); const selectedSeatsCount = selectSeats.length; $('#count').text(selectedSeatsCount); $('#total').text(selectedSeatsCount * ticketPrice) ; }); } ``` 6. 使用local Storage儲存已選的座位,並將其取出後附加屬性 為了使頁面重整後依然能夠保有選取的位置,在每次選取時將內容儲存至瀏覽器的儲存空間,需要時再取出套用其他屬性。 - 使用JSON.parse把JSON資料轉換array回來,使用getItem到我們要使用的key(`selectedSeats`)取得value並且指派給變數selectedSeats - 使用兩個判斷式 - 第一個判斷式:條件為`selectedSeats`不為空值,且`localStorage`至少需要一個值。 - 通過第一個判斷式會透過`each()`方法,檢查`selectedSeats`索引值是否存在其中。 - 第二個判斷式:要是透過`indexOf()`確認索引值存在其中,indexOf會大於-1 - 通過第二個判斷式就會加上屬性`selected` ```.js= const selectedSeats = JSON.parse(window.localStorage.getItem('selectedSeats')); //將localStorage的資料加入 selected屬性 if(selectedSeats !== null && selectedSeats.length >0){ seats.each(function(index, seat){ //indexOf> -1代表該資料在arr 中 if(selectedSeats.indexOf(index)>-1){ seat.classList.add('selected'); } }); }// 在jquery裡 foreach的方式是 .each(function(index,element))和JS相反,js是foreach(function(element, index)) const selectedMovieIndex =window.localStorage.getItem('selectedMovieIndex'); if(selectedMovieIndex !== null){ $('#movie').selectedIndex = selectedMovieIndex; }; } ``` ###### tags: `javascript` `jQuery`