iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0

05 - Flex Panel Gallery

專案簡介

第五天要學習的目標是熟悉 flex 的應用,以及認識 CSS 選擇器偽類別、切換 class 用的 toggle

要做到切完版後,點擊不同的區塊會有放大及上下文字滑入的動畫

課程影片:JS30 05
導讀影片:Alex

初始文件

Github 檔案位置:05 - Flex Panel Gallery

網頁一開始的樣子如下

可以先去看看 最後的成品 如下

正式製作

流程

將程式的要求拆分步驟後,我們需要做的事情如下

  1. 設定 Flex 的屬性做好切版及文字置中
  2. 以偽元素和 CSS 選擇器撰寫 CSS 動畫
  3. 以 JS 監聽 click 事件,添加 CSS Class

設定 Flex 的屬性

在開始使用 Flex 前建議大家先破關 FLEXBOX FROGGY,裡面有 24 個 Flex 小遊戲

首先我們先幫主體的 .panels{} 加上 display: flex 讓顯示轉為橫向

.panel{} 加上 flex: 1 利用 flex 的屬性自動等分填滿主體範圍

.panel{}上利用 flex 屬性的 flex-directionjustify-content: center;,讓文字置中對齊(使用前要先display: flex

.panel{
    display: flex;
    flex-direction: column;
    justify-content: center;
}

最後,以 * 通用選擇器.panel 中的所有元素加上以下屬性,一樣是等分填滿和垂直平行置中對齊

.panel > * {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

偽元素和 CSS 選擇器撰寫 CSS 動畫

這裡利用偽類別中的 :first-child:last-child 單獨把上下兩段文字藏起來,以及寫好等等要做文字滑動特效的 class(此處選取的方式是 > 子代選擇器.class 類別選擇器),

.panel > *:first-child{ transform: translateY(-100%); }
.panel.open-active > *:first-child{transform: translateY(0);} 

.panel > *:last-child{ transform: translateY(100%); }
.panel.open-active > *:last-child{transform: translateY(0);}

並利用 flex 靈活排版的特性,做簡單的 item CSS 放大動畫 class

.panel.open {
  flex: 5;
  font-size: 40px;
}

以 JS 監聽 click 事件,添加 CSS Class

先利用前幾天學到的東西寫好 .panelclick 事件監聽

const panels = document.querySelectorAll('.panel');
    
function toggleOpen(){
  console.log(this);
}

panels.forEach(panel => {
  panel.addEventListener('click', toggleOpen);
});

這次比較不一樣的是,我們沒有使用 classList.addclassList.remove 兩個函式做 class 的添加和移除

而是用了 classList.toggle() 函式,他可以判斷 class 的有無而做開關,不需要拆分為 add 和 remove

function toggleOpen(){
  console.log(this);
  this.classList.toggle('open');
  this.classList.toggle('open-active');
}

如果我們想要等 item 完整的放大完再讓兩行文字飄進來的話,可以再利用之前學到的 transitionend 事件

要特別注意的是 flex 屬性在 TransitionEvent 中的 propertyName,部分瀏覽器名稱是 "flex",部分是 "flex-grow",因此我們可以用昨天剛學到的 .includes('flex') 處理

function toggleActive(e){
  console.log(e.propertyName);
  if(e.propertyName.includes('flex')){
    this.classList.toggle('open-active');
  }
}

panels.forEach(panel => {
  panel.addEventListener('transitionend', toggleActive);
})

最後程式碼

CSS

.panels {
  min-height: 100vh;
  overflow: hidden;
  display: flex;
}

.panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  flex: 1;
/*   省略... */
}

.panel > * {
/*margin: 0;
  width: 100%;
  transition: transform 0.5s; */
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.panel > *:first-child{ transform: translateY(-100%); }
.panel.open-active > *:first-child{transform: translateY(0);}
.panel > *:last-child{ transform: translateY(100%); }
.panel.open-active > *:last-child{transform: translateY(0);}

.panel.open {
  flex: 5;
  font-size: 40px;
}

JS

const panels = document.querySelectorAll('.panel');

function toggleOpen(){
  console.log(this);
  this.classList.toggle('open');
}

function toggleActive(e){
  console.log(e);
  if(e.propertyName.includes('flex')){
    this.classList.toggle('open-active');
  }
}

panels.forEach(panel => {
  panel.addEventListener('click', toggleOpen);
});

panels.forEach(panel => {
  panel.addEventListener('transitionend', toggleActive);
})

完成結果圖

最後的成品

結語

以上是第五天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<

Flexbox + JavaScript Image Gallery — #JavaScript30 5/30
[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽:Day 5:Flex Panel Gallery
MDN Web Docs


上一篇
JS30 -> 04 - Array Cardio Day 1
下一篇
JS30 -> 06 - Type Ahead
系列文
剛接觸前端一個月的小白 - JavaScript30 挑戰筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言