前言
JS 30 是由加拿大的全端工程師 Wes Bos 免費提供的 JavaScript 簡單應用課程,課程主打 No Frameworks、No Compilers、No Libraries、No Boilerplate 在30天的30部教學影片裡,建立30個JavaScript的有趣小東西。
另外,Wes Bos 也很無私地在 Github 上公開了所有 JS 30 課程的程式碼,有興趣的話可以去 fork 或下載。
本日目標
利用 flexbox、transition 等 CSS 屬性,搭配 JS 監聽 transitionend、click 事件,最終實作出一個美觀的 Image Gallery。

解析程式碼
HTML 部分
由最外層的.panels包覆住內部的5個.panel所形成的一個巢狀結構。
| 1 | <div class="panels"> | 
CSS 部分
(僅說明影片中更動的部分)
先將最外層的 .panels 顯示類型設定為 flex,它同時也作為一個 flex-container 包覆住內部的五個 flex-items 也就是 .panel。
| 1 | .panels { | 
flex 是 flex-grow、flex-shrink、flex-basis 的簡寫,只有指定一個值給 flex 時,則代表設定的是 flex-grow,其餘屬性以預設值帶入。
flex-grow 可以指定 flex-container 的剩餘空間該如何分配,下面所有的 .panel 的 flex-grow 都是 1,也就是均勻分配剩餘空間。
接著,將每一個 .panel 的顯示類型都設定為 flex (此時的.panel 對下面的<p></p>來說就是 flex-container) 並將其下的 flex-item 在水平、鉛直方向都置中。
最後,設定 flex-direction 將 flex-box 的 main-axis 更改為直列。
| 1 | .panel { | 
將 .panel (flex-container)下的 <p></p> (flex-item) 的 flex 屬性設定為 1、0、auto,也就是均勻分配 flex-container 的剩餘空間、flex-item 長度超過 flex-container 時的收縮量設為 0、flex-item 在 flex container 的初始大小設為自動(auto)。
接著,也將<p></p>當作是一個 flex-container,設定顯示類型為 flex。透過 justify-content、align-items,將標籤內的文字(flex-item) 水平、鉛直置中排列。
| 1 | .panel > * { | 
初始狀態,分別將在 .panel 上方和下方的 <p></p> 都各上移、下移 100% 以達到隱藏的效果。
| 1 | .panel > *:first-child{ | 
接著設定當.panel上有open-active這個 class 時,就將原本隱藏的文字分別下移和上移顯示出來。
| 1 | .panel.open-active > *:first-child{ | 
.panel開啟時,將內部文字放大為 40px 並將 flex-container 剩餘分配的位置變為原來的5倍。
| 1 | .panel.open { | 
補充資料:
CSS flex 屬性
圖解 Flexbox 基本屬性
FLEXBOX FROGGY-學習 flexbox 的小遊戲
JS 部分
取得所有的.panel 並放到 NodeList 'panels' 中。
| 1 | const panels = document.querySelectorAll('.panel'); | 
為 panels 中的每一個.panel都註冊兩個事件監聽器,當 click 或 transitionend 事件發生時,就分別以 toggleOpen 和 toggleActive 方法進行事件處理。
| 1 | panels.forEach(panel => panel.addEventListener('click',toggleOpen)); | 
點擊任意一個.panel,toggleOpen() 方法會替觸發事件的.panel依照情況的不同,新增或是移除.open 這個 class,若是觸發事件的.panel原本沒有.open則新增,有的話則移除.open。
當 transitionend 事件發生,toggleActive() 會作出如同 toggleOpen() 一樣的判斷,決定新增還是移除.open-active這個 class。因為同時會被觸發的 transitionend 事件有很多個,我們決定在觸發 transitionend 事件的 CSS 屬性是 flex 時,才採取處理。為什麼不寫 e.propertyName == 'flex-grow' 是因為在 Safari 顯示的是 flex 而 Chrome、FireFox 顯示的是 flex-grow,為避免這個差異導致錯誤,我們可以使用 include(‘flex’),當 propertyName 含有 flex 就進行事件處理。
| 1 | function toggleOpen(){ |