JavaScript30 為Wes Bos推出的一項為期30天的挑戰,旨在幫助人們用純JavaScript來實現效果,初學者若想在JS方面快速精進,不妨一試。本題為第五題。
實現效果
點選任意一張圖片,圖片放大X倍,同時圖片上下兩方飛入文字,再點選已經展開的圖片後,圖片被壓縮,同時頂端和底部的文字飛出。檢視我的程式碼和demo。
頁面基礎佈局
觀察文件初始佈局:在類名為.panels
的父元素div
之下,有5個類名為.panel
的子div
,這5個div
內均包含3個p
標籤。文件內也已提供CSS
樣式及動畫,做題者只需稍許補充並新增監聽事件即可。
<div class="panels">
<div class="panel panel1">
<p>Hey</p>
<p>Let's</p>
<p>Dance</p>
</div>
......
<div class="panel panel5">
<p>Life</p>
<p>In</p>
<p>Motion</p>
</div>
</div>
複製程式碼
解題思路
CSS部分:
在本章中,大量運用flex
佈局知識,如需補課,推薦查閱阮一峰大神的部落格:
- 設定父元素也就是最大的容器
.panels
為display:flex
,預設專案沿主軸方向,從左到右排列; - 設定每個子元素即容器成員
.panel
為display:flex
,並設定屬性:- 設定
flex: 1
,flex
為flex-grow
,flex-shrink
和flex-basis
的簡寫; - 設定
justify-content: center
,該屬性規定專案在主軸上的對齊方式,center
即沿主軸居中排列。 - 設定
flex-direction: column
,該屬性定義主軸的方向(即專案的排列方向),column
表示主軸為垂直方向,起點在上沿; - 設定
align-items: center
,即專案在交叉軸上居中對齊。
- 設定
- 設定點選圖片後,文字的移動樣式;
- 設定點選圖片後,圖片的
flex
值。
JS部分:
- 獲取所有類名為
.panel
的元素; - 為其新增
click
監聽事件,觸發呼叫函式,新增或去除樣式,實現圖片拉伸或壓縮的效果; - 為其新增
transitionend
監聽事件,觸發呼叫函式,新增或去除樣式,實現頂端及底部文字飛入或飛出效果。
CSS部分程式碼
html {
box-sizing: border-box;
background: #ffc600;
font-family: 'helvetica neue';
font-size: 20px;
font-weight: 200;
}
body {
margin: 0;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
.panels {
min-height: 100vh;
overflow: hidden;/*內容溢位元素框時,內容會被修剪,並且其餘內容不可見 */
display: flex;
}
.panel {
background: #6B0F9C;
box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.1);
color: white;
text-align: center;
align-items: center;
/* 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;
font-size: 20px;
background-size: cover;
background-position: center;
flex: 1;
justify-content: center;
display: flex;
flex-direction: column;
}
.panel1 {background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500);}
......
.panel5 {background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500);
}
/* Flex Items */
.panel>* {
margin: 0;
width: 100%;
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 p {
text-transform: uppercase;
font-family: 'Amatic SC', cursive;
text-shadow: 0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
font-size: 2em;
}
.panel p:nth-child(2) {
font-size: 4em;
}
.panel.open {
flex: 5;
font-size: 40px;
}
複製程式碼
JavaScript完整程式碼:
const Panels = document.querySelectorAll('.panel');
function clearOpen() {
Panels.forEach(panel => panel.classList.remove('open'))
}
function toggelOpen() {
this.classList.toggle('open');
}
function toggleActive(e) {
if (e.propertyName.includes('flex')) {
this.classList.toggle('open-active')
}
}
Panels.forEach(panel => panel.addEventListener('click', toggelOpen));
Panels.forEach(panel => panel.addEventListener('transitionend', toggleActive));
複製程式碼
知識點
Flex佈局:
採用 Flex 佈局的元素,稱為 Flex 容器。它的所有子元素自動成為容器成員,稱為 Flex 專案。容器預設存在兩根軸:水平的主軸main axis
和垂直的交叉軸cross axis
。
Flex容器屬性:
flex-direction
屬性決定主軸的方向(即專案的排列方向);flex-wrap
屬性定義,如果一條軸線排不下,如何換行;flex-flow
屬性是flex-direction
屬性和flex-wrap
屬性的簡寫形式;justify-content
屬性定義了專案在主軸上的對齊方式。align-items
屬性定義專案在交叉軸上如何對齊。align-content
屬性定義了多根軸線的對齊方式。如果專案只有一根軸線,該屬性不起作用。
Flex專案屬性:
order
屬性定義專案的排列順序。數值越小,排列越靠前,預設為0。flex-grow
屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大。flex-shrink
屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小。flex-basis
屬性定義了在分配多餘空間之前,專案佔據的主軸空間。flex
屬性是flex-grow
,flex-shrink
和flex-basis
的簡寫,預設值為0 1 auto
。align-self
屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items
屬性。
介紹完基礎知識再看本題就清晰很多了,本題巢狀了三個Flex容器,分別為:
.panels
:使得子元素.panel
橫向等分排列;.panel
:使得其中的<p>
縱向等分排列;p
:使得其中的文字垂直水平居中分佈。 不過以上對Flex的介紹還不算詳細,若想深入瞭解,可查閱這裡。
translateY
為實現頂端及底部文字飛入飛出的效果,題中使用了一個用法,即transform: translateY,可實現元素在Y軸方向上移動。