前言
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(){ |