「JS30紀錄&心得」05 - Flex Panel Gallery

主題

用CSS與JS來製作一個點擊後會動畫展開的圖片展示效果,
運用到了CSS的flex、transform、transition.. 這篇比較偏向css知識!

[DEMO][GitHub][JavaScript30全列表]

步驟

Step1

由於整體HTML的tag是由1個panels包覆5個panel
為了使其設定為flex,先在外層容器panels加上display: flex
接著為每個panel加上flex: 1來使各子元件最大占比為1
也就會變成同容器中的5個元件都設1,那就是每個元件最大占比為20%。
(因對flex並不熟悉,我是用占比來理解,若有錯請在指正..感謝@@)

Step2

在為panel加上justify-content: center使其水平置中,
並在加上了display: flexflex-direction: column
再加上一層display: flex可以使panel底下的元件也變成flex控管

Step3

對panel底下的first-childlast-child做位移效果,
使其能在預設狀態於可視範圍外,並設計open-active
當觸發時,配合transition產生移回原位的動畫,
也在.panel.open中新增了flex: 5使其觸發時會有展開的動畫。

Step4

編寫JS先取得所有panel的節點,
接著設計toggle function使執行的物件藉由.classList.toggle來新增/移除動畫class
並透過addEventListener來監測當click&transitionend時觸發toggle function。

.classList&transitionend&toggle在>第一篇<剛好有提到。

Javascript語法&備註

e.propertyName & includes()

在範例中,觸發動畫效果的順序為:

  1. click其中一張圖(panel)觸發addEventLinstner中的toggleOpen
  2. 為其增加.open,增加Flex: 5的效果,同時也是使用了.panel中的transition: flex這段
  3. .opentransition結束時,觸發了transitionend來作動toggleActive
  4. 為其增加.open-active效果,讓原本可是範圍外的p文字滑入

順序:4時有個判斷,

1
2
3
4
5
function toggleActive(e) {
if (e.propertyName.includes('flex')) {
this.classList.toggle('open-active');
}
}

e.propertyName可以抓到觸發transitionend的屬性名稱,
.open中觸發的transition屬性有兩個,分別為fontflex
要使其在flex之後在觸發的話,就要判斷進來的是不是flex
但因為transition: flex 0.7s..這段在sarafi是flex,而其他瀏覽器為flex-grow
所以不能用e.property === 'flex'來寫,會使其中一方瀏覽器抓不到值,
作者提到因為兩者都有flex的字眼,所以利用.includes('flex')來判斷, 只要e.property`有包含到flex的字串就使其通過判斷,加入動畫效果。

參閱:MDN-String.prototype.includes()

CSS語法&備註

flex

flex我目前還不熟,他還在我的待讀清單中XD
僅依據目前這篇使用到的做筆記:

display: flex

把該容器設定為flex模式,可以在其他flex中設定(角色為子元素時)

flex: flex-grow flex-shrink flex-basis

flex的簡寫,第一個為占比、第二個為壓縮值、第三個為默認尺寸

flex-direction

flex排列的方向,colume(垂直向)或row(水平向),預設為row

行與列的中文用法,我自己有點混淆
像是我會說第314行要加個分號喔,也會說工具列上第3個icon
兩者都是在描述水平向,但我卻用了不同的字去形容囧

justify-content & align-items

依據flex-direction設定的主/側軸來決定排列方式,
例如設定flex-direction: row那麼
justify-content: center就指水平置中,
align-items: center代表垂直置中。
參閱:MDN-CSS Flexible Box Layout

:first-child() & :last-child()

CSS的:偽類別,分別可以選取first(第一個)/last(最後一個)子元素,
在範例的panel中,除了主圖的大字外,上下各有一個p包含了點擊後進場的動畫文字:

1
2
3
4
5
<div class="panel panel1">
<p>Hey</p>
<p>Let's</p>
<p>Dance</p>
</div>

透過panel > *:first-child選取Hey
透過panel > *:last-child選取Dance

探索

當展開其中一個時,在點其他的panel並不會關閉第一個已展開的效果,
若要達到每次點擊都是一個聚焦效果(關閉其他已展開的)的感覺得話,
我是這麼做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
//宣告一個上次點擊的Panel,預設先給他panels
let lastClickPanel = document.querySelector('.panels');

function toggleOpen() {
//每次檢查進入的element與上次進入的element是不是相同
//若不相同,則把上次點擊的element移除opev效果
//再把lastClickPanel指向為這次的elment
if (this !== lastClickPanel) {
lastClickPanel.classList.remove('open');
lastClickPanel = this;
}
this.classList.toggle('open');
}