JavaScript 카운트다운 타이머 (소스 코드)

카운트다운 타이머는 여러 용도로 사용이 가능하지만, 제 경우에 카운트다운 타이머는 시간을 적절히 정하고 그 시간내에 목표를 이루기 위해 집중하는 데에 도움이 되는 도구입니다.
'나만의 카운트다운 타이머'라는 콘셉트로 만들기 시작했습니다. 이것저것 넣고 싶은 기능이 많았지만 시간 관계상^^; 가장 기본적인 기능만을 구현하는 것으로 끝을 맺었습니다. 로컬에서 사용할 분은 이대로 사용하거나 코드를 변경·추가해서 자신만의 카운트다운 타이머를 만들어 보세요.
카운트다운 타이머 데모 페이지
데모 웹 페이지는 여기입니다.
데모 페이지 소스 코드
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<title>카운트다운 타이머</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/> | |
<meta name="description" content="심플한 카운트다운 타이머로 일의 능률을 높여 보세요!"/> | |
<!-- | |
[외부 라이브러리] | |
1. Bootstrap 4 (CSS만, 디자인) | |
2. Picker.js (날짜·시간 설정 다이얼로그) | |
3. EasyTimer.js (타이머) | |
--> | |
<link href="https://cdn.jsdelivr.net/combine/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css,npm/pickerjs@1.2.1/dist/picker.min.css" rel="stylesheet"/> | |
<script src="https://cdn.jsdelivr.net/combine/npm/pickerjs@1.2.1/dist/picker.min.js,npm/easytimer.js@4.3.0/dist/easytimer.min.js"></script> | |
<style> | |
.time-picker, .values { | |
background-color: #2962ff; | |
color: #ffffff; | |
text-align: center; | |
font-size: 5rem; | |
font-weight: bold; | |
border: none; | |
margin-bottom: 2rem; | |
font-family: monospace; /* 고정폭 */ | |
} | |
#ongoing-status, #completed-status, .values, #btn-group-2, #resume-btn { | |
display: none; | |
} | |
#ongoing-status, #completed-status, #btn-group-1, #btn-group-2 { | |
text-align: center; | |
} | |
.btn-light { | |
width: 120px; | |
margin-right: 10px; | |
color: #2962ff !important; | |
} | |
.picker-opened > .picker-dialog { | |
top: 13rem; | |
} | |
</style> | |
</head> | |
<body style="background-color: #448aff; padding-top: 6.5rem"> | |
<main role="main"> | |
<!-- 설정한 카운트다운 시간 표시 --> | |
<input type="text" class="form-control time-picker vw-100" value="00:01:00"> | |
<!-- 카운트다운 '진행 중' 표시 --> | |
<div id="ongoing-status"> | |
<div class="spinner-border text-light" role="status"></div> | |
</div> | |
<!-- 카운트다운 완료 표시 --> | |
<div id="completed-status"> | |
<div class="spinner-grow text-light" role="status"></div> | |
</div> | |
<!-- 카운트다운 표시 --> | |
<div class="form-control values vw-100"></div> | |
<!-- 버튼 그룹 1 --> | |
<div id="btn-group-1"> | |
<button id="set-btn" class="btn btn-light rounded-pill"> | |
시간 설정 | |
</button> | |
<button id="start-btn" class="btn btn-light rounded-pill"> | |
시작 | |
</button> | |
</div> | |
<!-- 버튼 그룹 2 --> | |
<div id="btn-group-2"> | |
<button id="cancel-btn" class="btn btn-light rounded-pill"> | |
취소 | |
</button> | |
<button id="pause-btn" class="btn btn-light rounded-pill"> | |
일시 정지 | |
</button> | |
<button id="resume-btn" class="btn btn-light rounded-pill"> | |
재개 | |
</button> | |
</div> | |
</main> | |
<script> | |
const timePicker = document.querySelector('.time-picker'); | |
const values = document.querySelector('.values'); | |
const btnGroup1 = document.querySelector('#btn-group-1'); | |
const setBtn = document.querySelector('#set-btn'); | |
const startBtn = document.querySelector('#start-btn'); | |
const btnGroup2 = document.querySelector('#btn-group-2'); | |
const cancelBtn = document.querySelector('#cancel-btn'); | |
const pauseBtn = document.querySelector('#pause-btn'); | |
const resumeBtn = document.querySelector('#resume-btn'); | |
const ongoingStatus = document.querySelector('#ongoing-status'); | |
const completedStatus = document.querySelector('#completed-status'); | |
// 시간 설정 다이얼로그 생성 | |
new Picker(timePicker, { | |
format: 'HH:mm:ss', // 시:분:초 | |
text: { | |
title: '시간을 설정하세요', | |
confirm: '확인', | |
cancel: '취소' | |
}, | |
}); | |
// 타이머 생성 | |
const timer = new easytimer.Timer(); | |
// 타이머 이벤트 리스너 등록 | |
timer.addEventListener('secondsUpdated', () => { | |
values.textContent = timer.getTimeValues().toString(); | |
}); | |
timer.addEventListener('started', () => { | |
values.textContent = timer.getTimeValues().toString(); | |
}); | |
timer.addEventListener('reset', () => { | |
values.textContent = timer.getTimeValues().toString(); | |
}); | |
timer.addEventListener('targetAchieved', () => { | |
values.textContent = '완료!'; // 카운트다운 완료 | |
ongoingStatus.style.display = 'none'; | |
completedStatus.style.display = 'block'; | |
btnGroup2.style.display = 'none'; | |
btnGroup1.style.display = 'block'; | |
}); | |
// 버튼 이벤트 리스너 등록 | |
/** | |
* ['시간 설정' 버튼] | |
* 경우1. 초기 화면에서 | |
* 경우2. 취소 후 | |
* 경우3. 완료 후 | |
*/ | |
setBtn.addEventListener('click', () => { | |
if (completedStatus.style.display === 'block') { | |
values.style.display = 'none'; | |
timePicker.style.display = 'block'; | |
completedStatus.style.display = 'none'; | |
} | |
timePicker.click(); | |
}); | |
/** | |
* [시작 버튼] | |
* 경우1. 초기 화면에서 | |
* 경우2. 취소 후 | |
* 경우3. 완료 후 | |
*/ | |
startBtn.addEventListener('click', () => { | |
timer.start({countdown: true, startValues: {seconds: toSeconds(timePicker.value)}}); | |
if (completedStatus.style.display === 'block') { | |
completedStatus.style.display = 'none'; | |
} else { | |
timePicker.style.display = 'none'; | |
values.style.display = 'block'; | |
} | |
ongoingStatus.style.display = 'block'; | |
btnGroup1.style.display = 'none'; | |
btnGroup2.style.display = 'block'; | |
}); | |
// 취소 버튼 | |
cancelBtn.addEventListener('click', () => { | |
// '일시 정지 > 취소 > 시작'인 경우 | |
if (timer.isPaused()) { | |
resumeBtn.style.display = 'none'; | |
pauseBtn.style.display = 'inline-block'; | |
} | |
timer.reset(); | |
timer.stop(); | |
values.style.display = 'none'; | |
timePicker.style.display = 'block'; | |
ongoingStatus.style.display = 'none'; | |
btnGroup2.style.display = 'none'; | |
btnGroup1.style.display = 'block'; | |
}); | |
// '일시 정지' 버튼 | |
pauseBtn.addEventListener('click', () => { | |
timer.pause(); | |
ongoingStatus.style.display = 'none'; | |
pauseBtn.style.display = 'none'; | |
resumeBtn.style.display = 'inline-block'; | |
}); | |
// 재개 버튼 | |
resumeBtn.addEventListener('click', () => { | |
timer.start(); | |
ongoingStatus.style.display = 'block'; | |
resumeBtn.style.display = 'none'; | |
pauseBtn.style.display = 'inline-block'; | |
}); | |
// '시:분:초'를 초로 계산하고, 그 결과값을 반환한다. | |
function toSeconds(hhmmss) { | |
const arr = hhmmss.split(':'); | |
return (+arr[0]) * 60 * 60 + (+arr[1]) * 60 + (+arr[2]); | |
} | |
</script> | |
</body> | |
</html> |
코드 설명
14~15행, 외부 라이브러리
[하나] Bootstrap(부트스트랩)
부트스트랩 홈페이지: https://getbootstrap.com
타이머 기능과는 상관이 없고 디자인을 위해서 사용되었습니다. 부트스트랩의 풀 버전을 사용하기 위해서는 JS(<script>)도 포함해야 하지만 여기에서는 필요하지 않으므로 CSS(<link>)만 포함했습니다.
[둘] Picker.js
Picker.js 홈페이지: https://fengyuanchen.github.io/pickerjs
<input> 요소를 통해서 날짜 또는 시간을 선택할 수 있는 기능의 사용자 인터페이스를 제공하는 자바스크립트 라이브러리입니다. GitHub(깃허브)를 통한 유지보수로 어느 정도 검증된 기능과 PC에서의 브라우저뿐만 아니라 모바일에도 어울리는 디자인을 겸비하고 있습니다.
[셋] EasyTimer.js
EasyTimer.js 홈페이지: https://albert-gonzalez.github.io/easytimer.js
타이머·크로노미터·카운트다운 기능을 제공하는 자바스크립트 라이브러리입니다. 여기에서는 카운트다운 기능을 사용합니다. 홈페이지에서 이 라이브러리의 사용법을 자세히 소개하고 있으며 GitHub를 통해서 유지보수를 진행 중입니다.
[CDN] jsDelivr(JS 배달)
CDN 서비스인 jsDelivr은 'Combine multiple files'라는 여러 외부 라이브러리들을 결합할 수 있는 기능을 제공하고 있는데, 그 기능을 활용한 코드가 바로 '14~15행'입니다.
'Combine multiple files' 소개글: https://www.jsdelivr.com/features#combine
댓글
댓글 쓰기