今天要製作一個點擊某區塊,該區塊的
首先先看看 css ,這裡的 css 很容易解析,就是一個 flex 容器包著另外一個 flex 容器,外層的是控制三行的排列,使用的 flex: 1 0 auto
表示三行等寬,在被添加 .open
時,會變成 flex: 3 0 auto;
。內層則是將上方的字 transform:translateY(-100%);
移到螢幕之上;下方的字 transform:translateY(100%);
移到螢幕之下,在父層得到 .open-active
會回到原本應該在的位置。
.panels {
overflow: hidden;
display: flex;
}
.panel {
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;
flex: 1 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.panel>* {
transition: transform 0.5s;
flex: 1 0 auto;
display: flex;
justify-content: center;
align-items: 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: 3 0 auto;
font-size: 40px;
}
首先我們選到所有的區塊 .panel
,並監聽 click
事件,在被點擊時加入 .open
和 .open-active
,
我們使用的是element.classList.troggle('.className')
,troggle()
是可以讓新增的className隨意的新增移除,這時候會發現,在區塊還沒完全打開時,字就已經跑出來了。這不是我們要的效果,我們希望「區塊完全打開後,字再跑出來」。
const panels = document.querySelectorAll('.panel');
function toggleOpen() {
this.classList.toggle('open');
this.classList.toggle('open-active');
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
因此,我們可以對區塊監聽 transitionend
事件,並且將添加 .open-active
移到這裡再執行即可。
這時候會發現和預想的不一樣,字並沒有跑出來。 這時候 console.log(e.propertyName);
發現有 flex-grow
和 font-size
兩個 transitionend
事件, toggle()
被執行了兩次,所以字又藏了回去。因此只要寫個判斷式讓觸法一次即可。
const panels = document.querySelectorAll('.panel');
function toggleOpen() {
this.classList.toggle('open');
}
function toggleActive(e) {
console.log(e.propertyName);
if (e.propertyName.includes('flex')) {
this.classList.toggle('open-active');
}
};
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
panels.forEach(panel => panel.addEventListener('transitionend', toggleActive));
特別要注意的是google和firefox都是使用flex-grow
,但是safari是使用flex
,因此使用flex
去篩選