今天要來做的主題還蠻有趣滴~ 如圖中所示,我們的目標水量是要把整個大杯子填滿(2L),點選下方的小杯子(250ml),可以把水加入大杯子中,並且顯示目前水量以及剩餘水量,跳杯子點選會把水量加再一起
知識點 | 使用說明 |
---|---|
flexbox | 設定水杯的排版 |
transition | 水量增加和減少的動畫 |
variable | 設定全域變數 |
知識點 | 使用說明 |
---|---|
querySelectorAll(selectors) | 取得每個 class 為 cup-small的杯子 |
forEach( ) | 迭代每個小杯子 |
addEventListener( ) | 為小杯子加入事件監聽 |
classList.add() / remove() | 新增與移除class="full" |
contains() | 回傳布林值,判斷A節點是否為B節點的後裔 |
nextElementSibling | 回傳下一個相鄰的element node(唯讀) |
<h1>Drink Water 沒事多喝水</h1>
<h3>今日目標:2L</h3>
<!-- 大杯子 -->
<div class="cup">
<!-- 剩餘量 -->
<div class="rest" id="rest">
<span id="liters">1.5L</span>
<small>剩餘量</small>
</div>
<!-- 飲水量-->
<div class="percentage" id="percentage">
20%
</div>
</div>
<p class="text">請選擇你喝了多少水</p>
<!-- 小杯子 -->
<div class="cups">
<div class="cup cup-small full">250 ml</div>
<div class="cup cup-small full">250 ml</div>
<div class="cup cup-small">250 ml</div>
<div class="cup cup-small">250 ml</div>
<div class="cup cup-small">250 ml</div>
<div class="cup cup-small">250 ml</div>
<div class="cup cup-small">250 ml</div>
<div class="cup cup-small">250 ml</div>
</div>
全域變數
全域變數是以 --
開頭,後面自定義變數名稱,並寫在:root
中,使之作用範圍為全域
在此我們設置兩個全域變數,以便之後要重複利用
:root {
--border-color: #144fc6; /*杯子的邊框顏色*/
--fill-color: #6ab3f8; /*水填滿的顏色*/
}
大局配置以及標題
* {
box-sizing: border-box;
}
body {
background-color: #3494e4;
margin: 0;
padding: 0;
display: flex; /*讓內容水平垂直置中*/
justify-content: center;
align-items: center;
flex-direction: column;
margin-bottom: 40px;
}
h1 {
margin: 10px 0 0;
}
h3 {
margin: 10px 0;
}
大杯子、小杯子
/* 大杯子以及小杯子的通用屬性 */
.cup {
background-color: #fff;
border: 4px solid var(--border-color);
color: var(--border-color);
border-radius: 0 0 40px 40px;
width: 150px;
height: 360px;
margin: 30px 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 小杯子 */
.cup.cup-small {
width: 50px;
height: 95px;
border-radius: 0 0 15px 15px;
background-color: rgba(255, 255, 255, 0.9);
cursor: pointer;
font-size: 14px;
margin: 5px;
align-items: center;
justify-content: center;
text-align: center;
transition: all 0.3s ease;
}
/* 裝小杯子的容器 */
.cups {
display: flex;
flex-wrap: wrap;
width: 250px;
align-items: center;
justify-content: center;
}
/* 填滿小杯子的水 */
.cup.cup-small.full {
background-color: var(--fill-color);
color: white;
}
剩餘的水量
/* 大杯子內剩餘的水量 */
.rest {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
flex: 1; /*flex-grow*/
transition: all 0.3s ease;
}
/* 1.5L */
#liters {
font-size: 20px;
font-weight: bold;
}
.rest small {
font-size: 12px;
}
紀錄你喝了多少水
/* 喝了多少水的 % 數 */
.percentage {
background-color: var(--fill-color);
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 30px;
height: 0; /*初始水量的高度設為0*/
transition: all 0.3s ease;
}
/* "請選擇你喝了多少水"字樣 */
.text {
text-align: center;
margin: 0 0 5px;
font-weight: bold;
}
以上都設定好,呈現會如下圖
那我們要把HTML中的部分程式碼刪除,因為要利用javaScript去控制
let cupSmall = document.querySelectorAll("cup-small"); /*回傳NodeList*/
let liters = document.getElementById("liters");
let percentage = document.getElementById("percentage");
let rest = document.getElementById("rest");
為每個小杯子加入事件監聽
cupSmall.forEach((cup, index) => {
cup.addEventListener("click", () => {
hightlightCups(index);
});
});
function hightlightCups(index) {
console.log(index); /*點按不同的小杯子會出現不同的數字,從0開始*/
// 減少水量
if (
cupSmall[index].classList.contains("full") &&
!cupSmall[index].nextElementSibling.classList.contains("full")
) {
index--;
}
cupSmall.forEach((cup, index2) => {
if (index2 <= index) {
cup.classList.add("full");
} else {
cup.classList.remove("full");
}
});
// 更新大杯子的水量
updateBigCup();
}
大杯子
function updateBigCup() {
let fullCups = document.querySelectorAll(".cup-small.full").length;
console.log(fullCups); /*滿杯的數量*/
let totalCups = cupSmall.length;
if (fullCups == 0) {
percentage.style.visibility = "hidden";
percentage.style.height = 0;
} else {
percentage.style.visibility = "visible";
percentage.style.height = `${(fullCups / totalCups) * 360}px`;
// 360為大杯子的高度
percentage.innerText = `${(fullCups / totalCups) * 100}%`;
}
}
當我杯子的水是100%時,會看到了以下這個奇景,"剩餘量"占了一行在那,那可以怎麼把它消滅掉呢??
其實很簡單,就是操控visibility的值而已,要隱藏就是"hidden",顯現就是"visible"
// 100%的水時,不要讓"剩餘量"占了一行的空間
if (fullCups === totalCups) {
rest.style.visibility = "hidden";
rest.style.height = 0;
} else {
rest.style.visibility = "visible";
liters.innerText = `${2 - (250 * fullCups) / 1000}`;
// 2為大杯子總容量(單位:公升), 250為一個小杯子的容量(單位:毫升),除以1000是要把毫升換算成公升制
}
附上codepen連結 https://codepen.io/hangineer/pen/QWrvxww
此賽project比較複雜的是要在大杯子和小杯子中間做切換,並且顯示剩餘和目前的水量,要怎麼將pjoject的流程寫得更清楚明白也是自己還在練習的,若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!那明天見囉
50 Projects In 50 Days - HTML, CSS & JavaScript