-
Day16. DrinkWaterUDEMY/50 Projects In 50 Days - HTML, CSS & JS 2024. 1. 12. 11:34728x90반응형SMALL
HTML
Drink Water <h1>Drink Water</h1>Goal : 2 Liters <h3>Goal: 2 Liters</h3>cup <div class="cup">remained <div class="remained" id="remained">liters <span id="liters">1.5L</span>remained <small>Remained</small>percentage <div class="percentage" id="percentage"></div>text <p class="text">Select How many glasses of water that you have drank</p>cup <div class="cups">cups * 8 <div class="cup cup-small">250ml</div>CSS
.cupborder-radius: 0 0 40px;.cup.cup-smallborder-radius: 0 0 15px 15px;.cup.cup-small.full{background-color: var(--fill-color);color: #fff;}js DOM을 이용해서 .full class를 붙일 경우 백그라운컬러와 폰트컬러를 변경.
<div class="percentage" id="percentage"></div>.percentage{background-color: var(--fill-color);display: flex;align-items: center;justify-content: center;font-weight: bold;height: 0;font-size: 30px;transition: 0.3s ease;}동작은 JS로 제어.
JS
const smallCups = document.querySelectorAll('.cup-small');작은 컵을 눌렀을 때 이벤트 발생을 위해 cu-small을 변수 smallCups에 적용
querySelectorAll을 통해 모든.cup-small 을 가져온다.
const liters = document.getElementById('liters');큰 컵에 채워지는 양의 비쥬얼 효과 발생 및 변경을 위해 liters을 변수 liters에 적용
하나의 클래스 liter만 가져온다.
const percentage = document.getElementById('percentage');채움 이벤트 발생시 얼마나 채워졌는지 비쥬얼 효과 발생 및 변경을 위해 percentage을 변수 percentage에 적용
const remained = document.getElementById('remained');
위의 이벤트 발생시 남은양에 대해 비쥬얼 효과 발생 및 변경을 위해 remained을 변수 remained에 적용
updateBigCup();smallCups.forEach((cup, idx) => {cup.addEventListener('click', () => highlightCups(idx));});function highlightCups(idx) {if (smallCups[idx].classList.contains('full') &&!smallCups[idx].nextElementSibling.classList.contains('full')) {idx--;}smallCups.forEach((cup, idx2) => {if (idx2 <= idx) {cup.classList.add('full');} else {cup.classList.remove('full');}});updateBigCup();}updateBigCup() 을 가장 먼저 호출하여 BigCup과 관련된 내용을 업데이트
smallCups.forEach((cup, idx) => {cup.addEventListener('click', () => highlightCups(idx));});smallCups의 배열을 반복하고 각 잔의 'click' 이벤트 리스너를 추가한다.
smallCups를 클릭하면 클릭된 잔의 인덱스를 매개변수로 하여 'highlightCups'의 함수를 호출
function highlightCups(idx) {if (smallCups[idx].classList.contains('full') &&!smallCups[idx].nextElementSibling.classList.contains('full')) {idx--;}smallCups.forEach((cup, idx2) => {if (idx2 <= idx) {cup.classList.add('full');} else {cup.classList.remove('full');}});updateBigCup();}highLightCups 함수를 정의한다.
클릭된 smallCups idx를 매개변수로 받는다.
highLightCups 함수 내부에서
클릭된 잔(samll cup) 이 이미 가득 차있고( classList.contains('full')), 다음 형제 요소{옆에 있는 잔(small cup)}가 가득 차있지 않다면, 인덱스를 감소.
(idx--)
forEach를 사용하여 모든 작은 잔(small cup)을 반복하고 인덱스(idx)까지의 잔에 'full' 클래스를 추가.
인덱스 이후의 잔은 'full' 클래스가 제거.
웹 페이지에서 시각적으로 잔을 채우고 비우는 효과 발생.
.cup.cup-small.full{background-color: var(--fill-color);color: #fff;}시각적 효과는 위의 css를 통해 발생 및 적용
function updateBigCup() {const fullCups = document.querySelectorAll('.cup-small.full').length;const totalCups = smallCups.length;
if (fullCups === 0) {percentage.style.visibility = 'hidden';percentage.style.height = 0;} else {percentage.style.visibility = 'visible';percentage.style.height = `${(fullCups / totalCups) * 330}px`;percentage.innerText = `${(fullCups / totalCups) * 100}%`;}
if (fullCups === totalCups) {remained.style.visibility = 'hidden';remained.style.height = 0;} else {remained.style.visibility = 'visible';liters.innerText = `${2 - (250 * fullCups) / 1000}L`;}}const fullCups = document.querySelectorAll('.cup-small.full').length;
작은 잔(small cup) 중 'full' 클래스를 가진 잔의 개수를 세어 fullCups에 저장.
작은 잔(small cup) 중 현재 채워진 잔의 수를 나타냅니다.
const totalCups = smallCups.length;
모든 잔(small cup)의 개수를 세어 totalCups 에 저장한다.
if (fullCups === 0) {percentage.style.visibility = 'hidden';percentage.style.height = 0;} else {percentage.style.visibility = 'visible';percentage.style.height = `${(fullCups / totalCups) * 330}px`;percentage.innerText = `${(fullCups / totalCups) * 100}%`;}if (fullCups === 0) { ... } else { ... }
만약 fullCups에 채워진 잔이 하나도 없다면,
percentage의 가시성을 숨기고 높이를 0으로 설정.
그렇지 않으면,
채워진 잔의 비율에 따라 percentage의 visibility와 height를 조정 및 텍스트를 설정
빈 잔 일 경우
percentage.style.visibility = 'hidden';percentage.style.height = 0;- percentage.style.visibility = 'hidden';: percentage 노출 결정
- percentage.style.height = 0;: percentage 엘리먼트의 높이를 0으로 설정
채워 질 경우
percentage.style.visibility = 'visible';percentage.style.height = `${(fullCups / totalCups) * 330}px`;percentage.innerText = `${(fullCups / totalCups) * 100}%`;1 / 8 * 330px = 41.25px
totalCups의 height 는 330px로 설정 즉 41.25 * 8 = 330px;
1 / 8 * 100 = 12.5%
logic
작은 컵을 누를 경우 event를 발생.
이벤트를 통해 큰 컵이 채워지는 효과 구현 및 remained 속성 값 변경.
toggle시 효과적용 효과제거 발생.
발생한 event 유지 및 처음 컵은 12.5%.
첫번 째 컵을 누르지 않고 두 번째 컵을 누를 경우 그 값을 중복하여 적용.
예를 들어 2번 째 컵을 누르면 25% 4번째 컵을 누르면 50% 마지막 8번 째 컵을 누르면 100% 적용.
즉 마지막 8번 째 컵을 눌러 100% 달성 효과 구현.
recap
큰 컵의 채워짐 효과를 어떻게 구현 했는가.
px 단위의 구현 이외의 다른 방법은!?
작은 컵의 중복효과를 제거하여 8번 째 컵을 누르면 100% 채울 수 있으나
중복효과를 제가해서 100% 채우기 위해 무조건 8번 눌러야 되는 상태로 변경하려면!?
728x90반응형LIST'UDEMY > 50 Projects In 50 Days - HTML, CSS & JS' 카테고리의 다른 글
Day18. Background Slider (0) 2024.01.12 Day17. MovieApp (0) 2024.01.12 Day15.IncrementingCounter (2) 2024.01.02 Day14. AnimatedNavigation (0) 2024.01.02 Day13. RandomChoicePicker (0) 2024.01.02