JS30-05-Flex-Panel-Gallery

JS-Event 與 CSS-Flex 的搭配使用

目標

  • 使用 CSS 的 flex、transform、transition.. 等屬性。
  • 透過 JS 監聽事件(click、transitionend),修改 CSS 類別(classList),達到不同效果。

實踐步驟

  1. 將 HTML 的 panels 底下的 5個panel,利用 flex 將版型排好

    • flex:flex-grow flex-shrink flex-basis
  2. 分別監聽(click、transitionend) 三個 panel

    • 利用 DOM.classList.toggle 新增、移除 CSS 類別

成品


See the Pen
JS30/05 - Flex Panel Gallery
by Bryan Hsaio (@bryan-hsaio)
on CodePen.


CSS 學習紀錄

flex: flex-grow flex-shrink flex-basis

在範例中,有運用到 Flex 的一個 css 屬性(flex),其參數如下

語法:

flex的簡寫參數
1
flex: flex-grow flex-shrink flex-basis;

屬性:

  • flex-grow:元件的伸展性
  • flex-shrink:元件的收縮性
  • flex-basis:元件的基準值

而在範例中,主要用到第一個參數 flex-grow,在此稍微說明其定義

元素全部加總的長度(600px) < 父元素的總長度(1000px) 時,
此時就有「剩餘的空間(1000 - 600 = 400)」,可以讓flex-grow依照比例去分配剩下的空間。

承上述,
若是 子元素全部的長度 >= 父元素的長度 時,
此時就「無剩餘的空間」可分配,這種情況下flex-grow 就無用了,

再承上述,
若 子元素總長度 超過 父元素長度時,有可能會造成跑版,
這時就可以用第二個參數 flex-shrink,來收縮子元素的長度。


JS 學習紀錄

event.propertyName

在監聽 transitionend 事件時,主要是判斷增加 Flex: 5 的效果是否已結束,
進而觸發另一事件,新增另一個 CSS 效果(文字滑入),
JS30-01-JavaScript-Drum-Kit已有練習使用過,在此重新複習一次。

圖:event.propertyName 取得 CSS 屬性名稱

includes

在影片中,作者有提到 transition: flex 0.7s.. 這一段,
在 sarafi 是 flex,而其他瀏覽器為 flex-grow,不過二個都有 flex這個字眼,
所以利用 .includes('flex') 來判斷 flex 的 css 效果 是否已結束。

CSS-flex名稱
1
2
3
4
5
6
.panel {
/* Safari transitionend event.propertyName === flex */
/* Chrome + FF transitionend event.propertyName === flex-grow */
transition: font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), flex 0.7s
cubic-bezier(0.61, -0.19, 0.7, -0.11), background 0.2s;
}
JS-includes
1
2
3
4
5
6
7
8
9
10
11
function toggleActie(e) {
// 因 Safari 和 Chrome + FF 顯示 propertyName 有差異
/* Safari transitionend event.propertyName === flex */
/* Chrome + FF transitionend event.propertyName === flex-grow */
// console.log(e);

if (e.propertyName.includes("flex")) {
// console.log(this);
this.classList.toggle("open-active");
}
}

延伸:點擊其他 panel 時,關閉已展開 panel

若目前畫面已有展開某一 panel 時,在點擊其他 panel 時,需要將前一個 panel 的 CSS 效果移除。

解法:

預達到此需求,我先想到 jQuery 的 .siblings() 可使用,但若想用純正的 Vanilla JS 達成,Javascript 有 Node.nextSiblingNode.previousSibling 可運用,
不過已經有別人造好輪子的話,那就…改用大神寫好的來使用,
感謝 get-elements-siblings-with-vanilla-javascript

移除鄰邊的CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function toggleOpen(e) {
// console.log(this);
this.classList.toggle("open");

// 移除鄰邊的CSS
// 參考網址:https://gomakethings.com/how-to-get-an-elements-siblings-with-vanilla-javascript/
// DOM.nodeType:元素中的空行或者空格會作為文本節點,返回"#text"
var sibling = this.parentNode.firstChild;
for (; sibling; sibling = sibling.nextSibling) {
if (sibling.nodeType !== 1 || sibling === this) continue;
// console.log(sibling);
sibling.classList.remove("open");
}
}

其他參考解法

GuaHsu 大大的思維:
紀錄最後一個點擊的 Panel,當下一次點擊的 Panel 不一樣時,則除移 CSS 效果。

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");
}