#14 - Increment Counter

primav·2024년 10월 1일

50Project

목록 보기
9/10
post-thumbnail

✨ HTML

아이콘 사용

✔️ 아이콘 사용할 수 있는 링크

 <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
      integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
      crossorigin="anonymous"
 />

✔️ 사용 방법
italic 태그를 사용하여 아이콘을 넣을 수 있다.
클래스 지정만 해주면 알아서 아이콘이 들어간다.

<i class="fab fa-twitter fa-3x"></i>
<i class="fab fa-youtube fa-3x"></i>
<i class="fab fa-facebook fa-3x"></i>

✨ CSS

폰트 사용

@import url("https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap");

:root {
	font-family: Roboto Mono
}

flex-basis

✔️ before

#container {
  box-shadow: inset 0 0 10px red;

  display: flex;
  justify-content: center;
  gap: 100px;
}

.item-container {
  box-shadow: inset 0 0 10px green;
  flex-basis: 200px;

  color: white;
  text-align: center;

  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
}

이렇게 초록색 아이템 박스들을 가장 큰 빨간색 컨테이너 안에 넣고, 각 아이템 박스들을 flex로 처리했다.

이때 flex로 처리한 이유는 여러 이유가 있지만,

  1. margin을 주는 것보다 gap을 주는 것이 더 편하겠다고 느낌
  2. flex-basis를 사용하여 창의 너비가 줄어들면 flex-shrink로 각 아이템의 너비가 줄어들게 하고 싶음

중에 2번 이유가 더 커서 각 아이템 박스를 flex로 처리했는데, item-container { flex-basis: 200px } 속성이 적용되지가 않았다.

👀 flex itemflex-basis가 적용 안되었을까?

부모 (flex-container)에 너비를 지정하지 않았기 때문이다.

flex-basis는 주어진 공간에서 각 flex item이 차지할 기본 너비를 설정하지만, 이 값이 제대로 작동하려면 부모 요소(flex container)가 공간을 명확히 정의해야한다.

✔️ after

#container {
  box-shadow: inset 0 0 10px red;

⭐️ width: 100%; ⭐️
  display: flex;
  justify-content: center;
  gap: 100px;
}

.item-container {
  box-shadow: inset 0 0 10px green;
  flex-basis: 200px;

  color: white;
  text-align: center;

  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
}

부모 요소에 너비를 100%으로 설정하여 flex item에게 공간을 할당해준다.
이 공간안에서 flex-basis, flex-shrink, flex-grow 등이 이루어지는 것이다.

🎯 flex 속성 사용 시, 부모에게 공간 할당은 필수이다!!


✨ JavaScript

생각한 방식

내가 생각했던 방식은 counter라는 모든 클래스를 가져와서 forEach 함수를 사용해 각각의 최댓값을 인덱스로 묶어주고 카운팅을 하는 것이었다.

카운팅 출력

✔️ before

let counters = document.querySelectorAll(".counter");
const maxValues = [12000, 5000, 7500];

counters.forEach((counter, idx) => {
  for(let i= 0; i < maxValues[idx]; i++) {
   		counter.textContent =  i;
  }
});

접근법은 좋았지만 내가 한 방식대로면 그냥 최댓값이 바로 출력되고 카운팅이 되는 모습이 화면에 나타나지 않았다.

for 루프 내에서 counter.textContent를 반복적으로 업데이트하기 때문에 최종적으로는 마지막 값만 표시된다.

👀 그러면 이 방식은?

그 다음으로 든 의문은, 그렇다면 반복문이 너무 빠르게 흘러가서 내가 원하는대로 진행은 되지만 결국 마지막 값만 남은 것 아닌가?

그래서 나는 이 반복문을 함수로 처리하고, setTimeout 을 이용하여 함수를 실행시키는 속도를 조절했다.

✔️ before

let counters = document.querySelectorAll(".counter");
const maxValues = [12000, 5000, 7500];

counters.forEach((counter, idx) => {
  const updateCounter = () => {
    for (let i = 0; i <= maxValues[idx]; i++) {
      counter.textContent = i;
    }
  };
  setTimeout(updateCounter, 1);
  updateCounter();
});

이렇게 진행하면 될 것 같았으나 결국 또 똑같은 결과가 나왔다.

자세히 생각해보니, 함수를 실행시키는 속도에 제어를 걸어도 함수 안에서 진행되는 for문이 돌아가는 속도는 내가 조절할 수가 없다.
이 for문이 너~무 빠르게 진행이 되니까 함수를 천천히 호출한다고 해도 결국 함수가 호출될때마다 마지막 값만 출력이 되는 것이다.

그래서 포기하고 다른 방식을 찾았다.

✔️ after

let counters = document.querySelectorAll(".counter");
const maxValues = [12000, 5000, 7500];

counters.forEach((counter, idx) => {
  let count = 0; // 카운트 초기화
  const increment = Math.ceil(maxValues[idx] / 200); // 매 프레임 증가 값 설정

  const updateCounter = () => {
    if (count < maxValues[idx]) {
      count += increment;
      console.log(count);
      if (count > maxValues[idx]) {
        count = maxValues[idx];
      }
      
      counter.textContent = count;
      setTimeout(updateCounter, 1); // if 안에 넣어 최댓값에 도달 안했을 때만 함수 호출
    }
  };

  updateCounter();
});

이 방식은 값을 증가시키는 함수를 만들고, 그 함수를 시간마다 호출하는 것이다.
전역 변수 (ForEach 안에서 전역변수라고 치겠다)로 count를 설정해두고 함수가 호출될 때마다 이 카운트는 증가하므로 함수가 호출될때마다 값이 변하고 화면에 출력된다.

그리고 이 방식을 진행하면 아까 내가 원했던 대로 함수를 원하는 시간마다 호출할 수 있다는 점이다.
아까는 for이라는 반복문 때문에 함수를 호출하는 시간은 내가 조절 했으나 함수를 호출할 때마다 얘가 미친듯이 돌아갔다면 이번엔 내가 함수를 호출할때마다 함수 안에서 이 작업이 한번씩만 일어날 수 있었다.

증가 값 설정

const increment = Math.ceil(maxValues[idx] / 200);

최댓값을 나눠서 얼만큼 증가시킬 것인지 정할 수 있다.
결국 if (count < maxValues[idx]) 라는 조건문 때문에 위의 증가값을 어떻게 설정하는지에 따라 함수가 호출되는 횟수가 다르다.

증가값 크게 설정하면 - 빠르게 최댓값에 도달 - 호출 횟수 줄어들음 - 빠르게 끝남
증가값 작게 설정하면 - 느리게 최댓값에 도달 - 호출 횟수 늘어남 - 느리게 끝남

따라서 밑의 빈칸의 역할이 중요하당 (증가값과 반대임 --> 저 값이 작아져야 증가값이 커지니까) (나누는 수 이므로)

const increment = Math.ceil(maxValues[idx] / ⭐️ 함수 호출 횟수 조절!!⭐️ );

setTimeout vs setInterval

setTimeout과 setInterval은 둘 다 JavaScript에서 비동기적으로 코드를 실행하기 위한 타이머 함수이지만, 동작 방식이 다르다.

setTimeoutsetInterval
사용 방법setTimeout(function, delay)setInterval(function, interval)
매개변수delay: 밀리초 단위의 지연 시간interval: 밀리초 단위의 실행 간격
실행 횟수한번만 실행반복 실행
작동 방식지정된 시간이 지난 후 한번만 함수를 실행지정된 시간 간격마다 반복해서 함수를 실행
중지 방법clearTimeout()clearInterval()

0개의 댓글