自學日記

學習程式相關知識及學習法

0%

作品練習-Movie Seat Booking

作品練習 :Movie Seat Booking

本練習作品學習要點為:將轉換成array的資料轉換進localStorage本地端,並使其保留在返還回介面UI上

HTML

簡單的快捷輸入法

1
2
3
4
5
6
7
8
9
10
11
12
<!--左側為縮寫輸入法/右側為輸入後顯示  -->
.row= <div class="row">
.seat*8= <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>
p.text= <p class="text"></p>
span#count= <span id="count"></span>

關於label的用法

label本身為表達語意的標籤,在表單上,用法常見為<label for>,以及與<select>連結的典型用法,於下方練習的code之後說明。

練習作品中的code呈現如下:

1
2
3
4
5
6
7
8
9
10
    <div class="movie-container">
<!-- 此為label典型用法 -->
<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>

關於

舉例:

1
2
3
4
5
6
<label for="male">Male</label>
<input type="radio" name="gender" id="male" value="male"><br>
<label for="female">Female</label>
<input type="radio" name="gender" id="female" value="female"><br>
<label for="other">Other</label>
<input type="radio" name="gender" id="other" value="other"><br><br>

呈現如右:

關於select用法(典型與label結合的用法)

舉例:

1
2
3
4
5
6
7
8
<label for="cars">Choose a car:</label>

<select name="cars" id="cars">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>

呈現如右:

參考自:

建立座位狀態

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--建立座位狀態 -->
<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>

建立電影螢幕及建立座位

藉由class命名來隨機標示座位狀態。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!--建立電影螢幕  -->
<div class="container">
<div class="screen"></div>
<!--建立座位 -->
<!--seat occupied為滿座 -->
<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>

總價格顯示:

span做id命名,作為後續計算座位及價格

1
2
3
4
5
6
7
<!--總價格顯示  -->
<!--下面兩個span標籤皆有命名id,為了後續操作幾個座位及總價格 -->
<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>

html完成圖如下

CSS

字型套用與通用選取器

1
2
3
4
5
6
7
<!--import css字型  -->
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');

<!--通用選取器:套用在全部元素標籤內 -->
*{
box-sizing: border-box;
}

body CSS樣式設定

1
2
3
4
5
6
7
8
9
10
11
12
body {
background-color: #242333;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
/* 套用上方import的字型 */
font-family: 'Lato', sans-serif;
margin: 0;
}

設定下拉式選單(select)樣式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.movie-container {
margin: 20px 0;
}

.movie-container select {
/* 背景 */
background: #fff;
/* 比較border: 0與none的差別 */
border: 0;
/* 圓角 */
border-radius: 5px;
/* 字體 */
font-size: 14px;
/* 距離左側間隔 */
margin-left: 10px;
/* 格子的長寬 */
padding: 5px 15px 5px 15px;
/* appearance屬性改變元素的外觀 */
/*此處為取消瀏覽器預設效果 */
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
}

比較border:0 與 border: none

  • border:0; 瀏覽器對border-width、border-color進行渲染,佔用記憶體。
  • border:none; 瀏覽器不進行渲染,不佔用記憶體。

請始終把border-style屬性宣告到border-color屬性之前,元素必須在改變顏色之前獲得邊框。

參考資料:
border:none和border:0px區別?

appearance屬性改變元素的外觀

此屬性能對任何元素的渲染風格改變,但因為目前這個功能各瀏覽器沒有統一,有些使用-moz-appearance或者使用-webkit-appearance,因此在設定上會兩者都設置,好讓各瀏覽器皆可運作,可運用於select選單、input輸入框、button按鈕等等。

可參考-moz-appearance property | -webkit-appearance property得知各瀏覽器支援的部分及appearance value。

以下列出幾個可能比較常使用的value:

1
2
3
4
5
6
7
8
9
10
11
12
{
-moz-appearance: none;
-moz-appearance: button;
-moz-appearance: checkbox;
-moz-appearance: scrollbarbutton-up;


-webkit-appearance: none;
-webkit-appearance: button;
-webkit-appearance: checkbox;
-webkit-appearance: scrollbarbutton-up;
}

參考資料:
使用CSS3的appearance屬性改變元素的外觀
MDN:-moz-appearance (-webkit-appearance)
appearance

transform與3D三維變化

以下分別介紹transform的rotateX()功能及
perspective功能。

transform的perspective效果

perspective是transform 3D轉換效果

在撰寫程式碼的時候,一度很疑惑,在container設定perspective 三維效果,但為何座位圖不會跟著有效果呢?(見下圖,座位row也是包在container裡面的)

A: 原來是因為screen設定了transform! 設定了transform三維效果才會有效!(此處特地將screen的css code放在一起一同說明)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.container {
/* 三維變化 3D效果變化*/
perspective: 1000px;
margin-bottom: 30px;
}
/*.screen {
background: #fff;
height: 70px;
width: 100%;
margin: 15px 0;

*此處設定了transform:

transform: rotateX(-45deg);
box-shadow: 0 3px 10px rgba(255, 255, 255, 0.7); */

參考自:
例項講解CSS3中Transform的perspective屬性的用法

transform的rotateX()效果

是transform 3D轉換效果,rotate X()為控制水平(X)軸,去進行變形。

參考自:
MDN-rotateX()

關於transform更多2D、3D效果請參考:
CSS 2D Transforms
CSS 3D Transforms

座位樣式設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 原來的.seat並無文字撐開,所以無寬度高度,
* 使用heigh所以無寬度高度,使用height、width、margin設定 */
.seat {
background: #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;
}
/*設定為橫排*/
/* .row {
display: flex;
} */

製作走道 :nth-of-type及:nth-last-of-type

使用:nth-of-type():nth-last-of-type()選擇器 ,目的是分類其中兩行座位產生間距,製造電影院走道的效果。

1
2
3
4
5
6
7
8

.seat:nth-of-type(2){
margin-right: 18px;
}

.seat:nth-last-of-type(2){
margin-left: 18px;
}

參考自:
:nth-of-type() & :nth-last-of-type() - 你覺得燒腦但其實根本不燒腦的選取器趴兔
比較:ntn-child:nth-of-type的大同小異:
CSS3:nth-of-type(n)

製作座位效果 :not選擇器與:hover選擇器

我們希望做座位圖稍微放大並有點選圖標效果,讓使用者體驗優化。

此處我們使用了兩個選擇器,分別是:not選擇器與:hover選擇器,

  • 透過:not選擇器,加入:not(類別名稱),可用來當成搜尋器的關鍵字排除器,會自動的略過該類別名稱,不套用樣式。
  • :hover 選擇器用於滑鼠箭頭滑到指定元素所顯現的效果,可用於所有元素,不限於link鏈接元素。
1
2
3
4
5
6
7
/*not與hover選擇器  */
.seat:not(.occupied):hover {
/* 更改圖標 */
cursor: pointer;
/* 座位圖形做放大 */
transform: scale(1.2);
}

參考自:
CSS3選擇器 :not() 讓CSS也支援判斷的機制
CSS :hover 选择器

showcase範例圖式移除hover效果

此處設定不讓hover設定的變化在shwcase版發生

1
2
3
4
5
/* 不讓hover設定的變化在shwcase版發生 */
.showcase .seat:not(.occupied):hover {
cursor: default;
transform: scale(1);
}

showcase座位狀態顯示樣式設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
.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 圖案與字之間的間隔(以字的左側去調整) */
.showcase li small {
margin-left: 2px;
}
/*於上方座位樣式已說明 */
.row {
display: flex;
}
/*於上方transform的perspective效果已說明 */
.screen {
background: #fff;
height: 70px;
width: 100%;
margin: 15px 0;
transform: rotateX(-45deg);
box-shadow: 0 3px 10px rgba(255, 255, 255, 0.7);
}

設定選取電影座位總數及總票價文字樣式

1
2
3
4
5
6
7
p.text {
margin: 5px 0;
}

p.text span{
color: #6feaf6;
}

完整Javascript

DOM元素宣告

  • ticketPrice,從const改成let,因value會更動(隨電影票價等更動)
  • parseInt函式為轉換語法,加了+號可將回傳值由字串轉換為數字
  • querySelector只返回匹配的第一個元素,如果沒有匹配項,返回null
  • querySelectorAll返回匹配的元素集合,如果沒有匹配項,返回空的nodelist(節點陣列)ex.返回”[]”。
  • (‘.row .seat:not(.occupied)’)同css選擇器,querySelectorAll也可以這樣使用排除不要的元素。
  • 將函式呼叫populateUI()’放置於前面,其一重點為:因函式提升的特性,函式呼叫放前放後沒有影響,其二重點為:放置於”Save Selected movie index and price”的function前面,目的是讓票價及位置在先前的紀錄中能被回傳,讓其資料持續保持在瀏覽器介面(UI)上。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // querySelector回傳匹配指定選擇器的第一個元素
    const container =
    document.querySelector('.container');
    // 有很多的seat,所以選擇querySelectorAll回傳所有的元
    // ('.row .seat:not(.occupied)')同css選擇器,querySelectorAll也可以這樣使用排除不要的元素
    const seats = document.querySelectorAll('.row .seat:not(.occupied)');
    const count = document.getElementById('count');
    const total = document.getElementById('total');
    // 先行說明movieSelect之HTML id=movie為字串,作為後續說明時更能幫助理解
    const movieSelect = document.getElementById('movie');

    // 呼叫下方 populateUI function,目的讓get到的本地端的資料放入(因為函式提升的特性,函式呼叫放前放後沒有影響)
    populateUI();

    // 小撇步:加了+號可將回傳值由字串轉換為數字(HTML id(movie)及value皆為字串)
    // 因Movie select event事件監聽中更換電影,票價會改變
    //所以從const改成let,因value(票價值)會更動
    let ticketPrice = +movieSelect.value;

    設定seat事件監聽,再設定seat toggle(切換)狀態

  • 使用if判斷,點擊空座位切換為selected,再點擊一次切換回未點擊狀態。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //Seat click event
    // 未設定if之前,點擊任何元素皆會回傳值
    container.addEventListener('click', e => {
    if (
    // 設定只有點擊seat,並且不是(語法:&&!)occupied才會返值
    e.target.classList.contains('seat') &&
    !e.target.classList.contains('occupied')
    ) {
    // classList.toggle,切換類設定,設定點擊空座位轉換為selected的css設定(turn blue color),再點擊時"切換"為未點擊時狀態,
    e.target.classList.toggle('selected');

    updateSelectedCount();
    }
    });

補充關於function(e)的部分:
e=Event,Event對象代表事件的狀態,比如事件在其中發生的元素、鍵盤按鍵的狀態、滑鼠的位置、滑鼠按鈕(click)的狀態。

事件通常與函數結合使用,函數不會在事件發生前被執行!

參考資料:
JS基礎篇–HTML DOM classList 屬性

設定總票價的數字變化

繼設定事件監聽來讀取座位數後,我們可以進一步去設定總票價的變化。

1
2
3
4
5
6
7
8
9
10
//Update total and count
function updateSelectedCount() {
// 選擇row底下含有seat.selected的物件,設定此會回傳nodlist(見下圖1)
const selectedSeats = document.querySelectorAll('.row .seat.selected');
// 將nodlist轉換成數字(見下圖2)
const selectedSeatsCount = selectedSeats.length;
// 設定顯示座位數及票價(見下圖3)
count.innerText = selectedSeatsCount;
total.innerText = selectedSeatsCount * ticketPrice;
}

圖1.點選座位,顯示nodlist

圖2.設定length,轉換成數字

圖3.設定點選座位就會顯示座位數及票價

設定選擇不同電影跳出不同票價

這裡在movieSelect(電影選擇列)上再設定一個監聽事件,觸發的點是’change’,使選擇不同電影可以同步更新到總票價區。

change=>物件內容改變時
target=>指向觸發事件的 DOM element
引用自JavaScript DOM Event (事件處理)

1
2
3
4
5
6
//Movie select event
//這裡因value會變化,所以上方宣告使用let
movieSelect.addEventListener('change', e => {
ticketPrice = +e.target.value;
updateSelectedCount();
});

參考資料:
JavaScript DOM Event (事件處理)
JavaScript 從零開始 - Day34- e.target 與 nodeName

將點選的座位儲存在本地空間

這裡描述的部分,主要是在頁面重新整理之後仍可以保留資料,我們希望將資料保存在本地儲存空間。

於updateSelectedCount函式內寫入

因解說方式關係,先附上完整code,因函式內有部分已於前段說明,因此以註解方式提醒讀者注意片段,將於下方一一拆解說明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Update total and count
function updateSelectedCount() {
const selectedSeats = document.querySelectorAll('.row .seat.selected');

// 此處為本次說明要點1:如何點選座位位置(為每個座位定上順序位置(索引位置))
const seatsIndex = [...selectedSeats].map(seat => [...seats].indexOf(seat));
// 說明要點2:儲存於本地空間(瀏覽器)
localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex));

const selectedSeatsCount = selectedSeats.length;

count.innerText = selectedSeatsCount;
total.innerText = selectedSeatsCount * ticketPrice;
}

如何點選座位位置(為每個座位定上順序位置(索引位置))

我們將思路拆解為:
1.Copy selected seats into array 將已選擇的座位轉換成陣列。
2.Map through array 對陣列元素進行處理
3.return a new array indexs 回傳陣列第幾個位置

1
2
3
4
5
6
// 此函式為es6簡化 另種寫法為const seatsIndex = [...selectedSeats].map(function(seat) { return [...seats].indexOf(seat)});
const seatsIndex =
// 稱為展開運算符,下方做詳細介紹
// 使用map()對陣列做處理,下方介紹
// indexOf()取締幾個位子的方法,下方介紹
[...selectedSeats].map(seat => [...seats].indexOf(seat));

Copy selected seats into array-展開運算符介紹

這個運算符後面必定接著一個陣列。最常見的是用來組合(連接)陣列,對應的陣列方法是concat。

範例:

1
2
3
4
5
const arr = [1,2,3]
const arr2 = [...arr,4,5]

console.log(arr2)
// arr2為1,2,3,4,5

資料參考:
展開運算符與其餘運算符

Map through array- 處理陣列元素 map()

陣列 (arrray) 的 map() 方法用來遍歷一個陣列中的每個元素,將元素分別傳入你指定的函數,最後將所有函數的返回值組成一個新的陣列。

語法:

1
2
3
const newArr = arr.map(function (value, index, array){
//do something...
});

範例:

1
2
3
4
5
6
7
8
9
10
11
var numbers = [1, 4, 9];

var doubles = numbers.map(function(num) {
return num * 2;
});

// 輸出 [2, 8, 18]
console.log(doubles);

// 輸出 [1, 4, 9]
console.log(numbers);

資料參考:
JavaScript Array map()

return a new array indexs -回傳第幾個位子: indexOf()

indexOf() 方法會找出第一個(第幾個)陣列中元素的索引位置,若不存在於陣列中則回傳 -1。

語法:ary.indexOf(searchElement)ary.indexOf(searchElement, fromIndex)

範例:

1
2
3
4
5
6
7
8
9
const arr = [1, 2, 3, 4, 4];

console.log(arr.indexOf(1));
// 0
console.log(arr.indexOf(2));
// 1
// 重複的元素,會以第一個為主,除非指定
console.log(arr.indexOf(4,2));
// 4

參考資料:
Array.prototype.indexOf()

設定localStorge 儲存於本地儲存空間(瀏覽器)

可以跨瀏覽器分頁做使用、使用者關掉分頁或瀏覽器再打開資料仍不會消失,且資料無期效限制,資料將永久被保留。

資料儲存的格式

  • 資料是以類似 JSON 的格式儲存
  • keyName(屬性名稱) 和 keyValue(相對應的值) 皆需要為字串,ex, keyName: ‘Name’/ keyValue:’Shawn’

存入資料語法:
localStorage.setItem(keyName, keyValue)

我們欲將選取的座位(selectedSeats)存入本地端,而點選的座位值(seatsIndex)為array(陣列),將其轉換為字串方能存入瀏覽器。

1
2
3
4
5
6
// 因分開說明,這裡再將上方解釋的程式補充於此,讓讀者更方便對應,localStorage取值的部分:
// const seatsIndex = [...selectedSeats].map(( seat => {return [...seats].indexOf(seat)}))
// keyName:'selectedSeats',keyValue為keyName對應的值,因其在上方函式已轉為陣列(array),所以使用JSON.stringify()轉換成字串(string)

// 'selectedSeats'為application顯式的名稱(見下圖)
localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex));

可於瀏覽器的檢查(shift+ctrl+i)中的application,找到儲存的seatsIndex。

localStorage同樣用法:於setMovieData函式使用

除了座位被儲存,選擇哪部電影及其票價,也同樣需要被存入本地儲存空間。
此次不同的地方在於,keyValue本身即為字串,不須使用JSON.stringify()轉換。

1
2
3
4
5
6
7
8
// Save selected movie index and price
// function放入參數:e.target.selectedIndex=movieIndex,
// e.target.value=moviePrice
function setMovieData(movieIndex, moviePrice) {
// 'selectedMovieIndex'及'selectedMoviePrice'為存入application顯示的名稱(可見下圖)
localStorage.setItem('selectedMovieIndex', movieIndex);
localStorage.setItem('selectedMoviePrice', moviePrice);
}

再設定上方函式之前,我們於movieSelect的監聽事件上再增加一行呼叫函式,以作為被觸發(此處為滑鼠點擊事件,即點選電影目錄)時,會存入localStorage。

1
2
3
4
5
6
7
8
9
10
11
//Movie select event
movieSelect.addEventListener('change', e => {
ticketPrice = +e.target.value;

//此行是此次localStorage函式前添加,其他addEventListener上方皆已說明。
// e.target.selectedIndex為
// 抓取瀏覽器(e)中點選目標(target)之值(此處為被點選之電影目錄索引值),而value則指票價值(html 中 option value = "票價值")。
// selectedIndex為取得select底下option tag的index(索引號)
setMovieData(e.target.selectedIndex, e.target.value);
updateSelectedCount();
});

補充說明:selectedIndex=>設定(set)或回傳(return)多個選擇的下拉式列表,它將僅返回選擇的第一個選項的索引(index)。
引用自HTML DOM Select 對象

設定之後,於瀏覽器中呈現如下:
(此範例中,我開啟檢查以方便做對比,我點選第一個Avengers電影,因此右側selectedMovieindex索引值為0(索引值從0起算),selectedMoviePrice為10(票價10))

參考資料:
JavaScript-localStorage 的使用
JS30-Day15-LocalStorage

從localStorage 取出資料,及回頭填充至UI(瀏覽器介面)

populateUI();函式呼叫放置在最上層的註解:”Save Selected movie index and price”的function前面,目的是讓儲存在本地端的資料能回傳放進瀏覽者介面中,得以持續保存及顯示,不因重新整理消失。

補充:持續顯示原因為本地端的資料”重新”各自放回選擇座位(seats)及選擇電影目錄(movieIndex)及電影票價(ticketPrice)等相關函式之中再計算、再判斷、再顯示於UI,最後跑到程式最後一行updateSelectedCount()呼叫函式,讓其重整網頁時,不需經過事件觸發,直接更新,所以看起來就如持續顯示一般。

撰寫populateUI();函式,使用localStorage 取出資料getItem()語法,

語法:
localStorage.getItem(key)

取出資料時,使用 JSON.parse() 方法,將資料轉換回原本的格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Get datd from localstorage and populate UI
function populateUI() {
//這邊使用parse把JSON資料轉換array回來,使用getItem到我們要使用的keyValue也就是剛剛我們設定的'selectedSeats'並且指派給變數selectedSeats
//往下做判斷式處理讓藍色座椅繼續留著,因為localstorage裡面儲存的資料符合條件
const selectedSeats = JSON.parse(localStorage.getItem('selectedSeats'));
//如果array selectedSeats不為空以及selectedSeats.length大於0則跑下面判斷式
if (selectedSeats ! null && selectedSeats.length > 0) {
//把所有座位使用forEach一個個印出並且判斷每個座位的index號碼是否跟selectedSeats的一樣,如果一樣則執行加上selected這個class
seat.forEach((seat, index) => {
// 陣列回傳-1,為undefined
if (selectedSeats.indexOf(index) > -1) {
seat.classList.add('selected');
}
});
}
//判斷selectedMovieIndex是否為空,不為空則執行重新賦值給selectedMovieIndex下拉式選單選取的電影index
const selectedMovieIndex = localStorage.getItem('selectedMovieIndex');

if (selectedMovieIndex ! null) {
movieSelect.selectedIndex = selectedMovieIndex;
}
}

// Initial count and total set
//會直接顯示出這個function的內容而不需要經過事件觸發保持讓事件重新整理後持續顯示
updateSelectedCount();

補充: map() v.s forEach()

map()特色為不會改變原陣列,而forEach()會修改原本陣列,另外forEach()沒有在使用return。

forEach適合於你並不打算改變數據的時候,而只是想用數據做一些事情– 比如存入數據庫或則打印出來。

範例:

1
2
3
let arr = [ "a" , "b" , "c" , "d" ]; 
arr.forEach( letter => { console .log(letter); }); // a // b // c // d

map()適用於你要改變數據值的時候。不僅僅在於它更快,而且返回一個新的數組。這樣的優點在於你可以使用複合(composition)(map(), filter(), reduce()等組合使用)來玩出更多的花樣。

範例:
讓範例更具變化,我們首先使用map將每一個元素乘以2,然後緊接著篩選出那些大於5的元素。最終結果賦值給arr2。

1
2
3
let arr = [ 1 , 2 , 3 , 4 , 5 ]; 
let arr2 = arr.map( num => num * 2 ).filter( num => num > 5 );
// arr2 = [6, 8, 10 ]

參考資料:
Day13【ES6 小筆記】Array.map() - 處理陣列最佳選擇
JavaScript中Map和ForEach的區別