Javascript_30_29

안녕하세요!

Derek 입니다 😃

점점 끝이 보이네요!

Day 29 project와 다음 편인 30번째 주제는 굉장히 재밌을거에요!

오늘은 스탑워치 기능을 구현해볼겁니다 :)

바로 시작해볼게요.




29. Countdown Timer

목표

20초, 5분, 15분, 20분, 60분 카운트 다운 기능을 구현한다. 하단의 Be Back At 으로 완료시 시간을 표싷고, 원하는 시간을 입력하게도 구현한다.

6개의 시간 슬롯에 대해서 카운트 다운을 구현했습니다!

하단에는 선택한 시간이 모두 지났을 때의 결과로, 약간 수업하다가 쉬는시간을 주어서 언제 다시 수업을 시작할건지.. 알려주는 기능이라고 보셔도 무방합니다.


Derek 과 Wes Bos의 구현코드

let countDown;
const timerDisplay = document.querySelector(".display__time-left");
const endTime = document.querySelector(".display__end-time");
const buttons = document.querySelectorAll("[data-time]");

function timer(seconds) {
    clearInterval(countDown);
    
    const now = Date.now();
    const then = now + seconds * 1000;

    displayTimeLeft(seconds);
    displayEndTime(then);

    countDown = setInterval(() => {
        const secondsLeft = Math.round((then - Date.now()) / 1000);

        if(secondsLeft < 0) {
            clearInterval(countDown);
            return;
        }
        displayTimeLeft(secondsLeft)
    }, 1000);

}

function displayTimeLeft(seconds) {
    const minutes = Math.floor(seconds/60);
    const remainerSeconds = seconds % 60;
    const display = `${minutes}:${remainerSeconds < 10 ? `0` : ``}${remainerSeconds}`;
    document.title = display;
    timerDisplay.textContent = display;
}

function displayEndTime(timestamp) {
    const end = new Date(timestamp);
    const hour = end.getHours();
    const adjustedHour = hour > 12 ? hour - 12 : hour;
    const minutes = end.getMinutes();
    endTime.textContent = `Be Back At ${adjustedHour}:${minutes < 10 ? '0' : ''}${minutes}`;
  }

function startTimer () {
  const seconds = parseInt(this.dataset.time);
  timer(seconds);
}

buttons.forEach(button => button.addEventListener("click", startTimer))

document.customForm.addEventListener('submit', function(e) {
  e.preventDefault();
  const mins = this.minutes.value;
  console.log(mins);
  timer(mins * 60);
  this.reset();
});

상당히 깁니다! 작게 쪼개서 정리해볼게요.

1. 변수 설명

let countDown;
const timerDisplay = document.querySelector(".display__time-left");
const endTime = document.querySelector(".display__end-time");
const buttons = document.querySelectorAll("[data-time]");
  • countDown : 추후에 사용될 setInterval 함수를 가지는 객체.
  • timerDisplay : 하단에 보이는 점점 줄어드는 시간을 표시하는 div element.
  • endTime : 남은 시간 표시 아래 Be Back At 으로 카운트 다운이 마치는 시간을 표시하는 p element.
  • buttons : 상단 5초, 20초, 등 타임 슬록 버튼 array.

이렇게 크게 4개의 변수가 사용됩니다.

2. displayTimeLeft 함수

이 함수는 초 단위의 시간값을 받아서 화면에 표시해주는 함수입니다.

그렇다면, 이렇게 유추할 수 있을 것 같아요.

매 초마다 실행되는 함수. -> setInterval 사용!

특정 시간마다 실행이 되어야하는 함수로 생각해도 될 것 같습니다.

function displayTimeLeft(seconds) {
    const minutes = Math.floor(seconds/60);
    const remainerSeconds = seconds % 60;
    const display = `${minutes}:${remainerSeconds < 10 ? `0` : ``}${remainerSeconds}`;
    document.title = display;
    timerDisplay.textContent = display;
}

인자로 넘어온 seconds 를 기반으로 남은 시간을 display 해줍니다.

minutesreaminerSeconds 를 알맞게 계산하여 백틱으로 표현해 display 변수에 넣고, 이를 textContent 로 표현했습니다.

3. displayEndTime 함수

2번의 displayTimeLeft 함수와 비슷합니다.

function displayEndTime(timestamp) {
    const end = new Date(timestamp);
    const hour = end.getHours();
    const adjustedHour = hour > 12 ? hour - 12 : hour;
    const minutes = end.getMinutes();
    endTime.textContent = `Be Back At ${adjustedHour}:${minutes < 10 ? '0' : ''}${minutes}`;
  }

다만, displayTimeLeft 와 다른 점은, timestamp 로 넘어온 인자는 실제 표시해야 하는 시간이라는 점입니다.

즉, 카운트 다운이 끝날 시점의 시간값이 timestamp 로 넘어오는 것이죠.

timestamp 를 단순히 내장함수로 조정하여 end, hour, adjustHour, minutes로 표현하여 textContent 로 표현합니다.

4. timer 함수

가장 중요한 타이머 함수입니다. 이 친구는 setInterval 함수를 가지고 2번과 3번 함수, 즉 displayTimeLeft, displayEndTime 함수를 수행합니다.

function timer(seconds) {
    clearInterval(countDown);
    
    const now = Date.now();
    const then = now + seconds * 1000;

    displayTimeLeft(seconds);
    displayEndTime(then);

    countDown = setInterval(() => {
        const secondsLeft = Math.round((then - Date.now()) / 1000);

        if(secondsLeft < 0) {
            clearInterval(countDown);
            return;
        }
        displayTimeLeft(secondsLeft)
    }, 1000);
}

먼저, setInterval 함수와 clearInterval 함수를 설명드릴게요.

4-1) setInterval, clearInterval 함수

먼저, setInterval 함수의 문법은 아래와 같습니다.

let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...)

[delay] 시간 마다 등록된 callback 함수를 실행시킵니다.

예시를 들어보면,

// 2초 간격으로 메시지를 보여줌
let timerId = setInterval(() => alert('째깍'), 2000);

// 5초 후에 정지
setTimeout(() => { clearInterval(timerId); alert('정지'); }, 5000);

참고로, setInterval 함수로 반환되는 값은 자연수(Number 타입)이며, 일종의 프로세스 아이디(pid) 라고 봐도 무방합니다.

그 프로세스 아이디를 clearInterval 함수로 넘겨주어 해당 프로세스를 중단시킬 수 있습니다.

그렇다면 displayTimeLeft 에서 사용된 함수를 보면,

countDown = setInterval(() => {
  const secondsLeft = Math.round((then - Date.now()) / 1000);

  if(secondsLeft < 0) {
    clearInterval(countDown);
    return;
  }
  displayTimeLeft(secondsLeft)
}, 1000);

then 이라는 변수에서 Date.now() 를 빼서 1000로 나누어 밀리세컨드로 변환합니다.

남은 시간을 displayTimeLeft 에 표시하면 됩니다! 그전에 만약 시간이 모두 흘러 0보다 작다면 clearInterval 함수를 통해 setInterval pid를 종료시켜요.


timer 함수에는 setInterval 함수 위에는 다음과 같은 코드가 있습니다.

clearInterval(countDown);

const now = Date.now();
const then = now + seconds * 1000;

displayTimeLeft(seconds);
displayEndTime(then);

이는 timer 함수를 실행하기 전에 등록되어 있는 setInterval 함수가 있다면 지우는 clearInterval 함수와, 현재시간과 고른 시간이 모두 흐른 시간을 계산하는 변수인 now, then 변수의 선언입니다.

이를 사용해 먼저 남은 시간과 종료시간을 display 합니다.

5. 이벤트 함수

이제 timer 함수를 사용해서 이벤트를 등록합니다.

function startTimer () {
    const seconds = parseInt(this.dataset.time);
    timer(seconds);
}

buttons.forEach(button => button.addEventListener("click", startTimer))

buttons 가 눌릴때마다 dataset 정보를 읽어서 seconds 변수에 넣어 timer 함수를 실행시킵니다.

잠깐 html 내용을 보여드리자면,

<button data-time="20" class="timer__button">20 Secs</button>
<button data-time="300" class="timer__button">Work 5</button>
<button data-time="900" class="timer__button">Quick 15</button>
<button data-time="1200" class="timer__button">Snack 20</button>
<button data-time="3600" class="timer__button">Lunch Break</button>

이렇게 data 속성으로 버튼이 구성되어 있습니다.

6. 시간 입력 기능

마지막으로 원하는 시간을 입력하여 카운트 다운 함수 수행입니다.

document.customForm.addEventListener('submit', function(e) {
  e.preventDefault();
  const mins = this.minutes.value;
  timer(mins * 60);
  this.reset();
});

위와 같습니다.

mins 라는 변수에 어떤 값을 넣어서 timer 함수를 실행시킵니다!

mins 변수를 설명하기 위해서는 html 설명이 필요할 것 같군요.

시간을 입력하는 html 부분은 아래와 같습니다.

<form name="customForm" id="custom">
  <input type="text" name="minutes" placeholder="Enter Minutes">
</form>

여기서 좀 특이한 사항이 있더라구요. Form 사용법을 참고하시면 form 태그에 대한 특별한 기능을 확인 할 수 있습니다.

간단하게 설명하자면 form 태그에 직접적으로 접근이 가능하다는 점입니다.

<form name="signUp" id="sign-up">
  <input type="text" name="newId" placeholder="아이디를 입력하세요." />
  <input type="submit" value="등록"/>
</form>

<script>
  // 폼 객체 'signUp'의 name="newId"인 요소 지정
  const signUpFormTxt = document.signUp.newId;
  // 폼 객체 'signUp'의 type="submit"인 버튼 요소 지정
  const signUpFormSbmt = document.signUp.submit;
</script>

@출처 : raram2님 velog

이렇게 form 태그의 name 속성에 바로 document 가 접근 가능하다는 점입니다.

이처럼 시간을 입력해서 카운트 다운하는 기능까지, 정리해보았습니다.




Date() 객체를 사용해서 시간을 표시하고, setInterval 함수를 통해 매 초마다 특정 함수를 실행하고 clearInterval 함수까지, 정리해보았습니다.

틀린내용이나 수정할 내용이 있다면 언제든지 피드백 부탁드립니다!

감사합니다!🤗

좋은 웹페이지 즐겨찾기