2318 단어
12 분
개발한 사이트 소스코드 해설
아래는 제가 짠 사이트의 코드 해설입니다. (이 포스트 작성하는데 1시간 걸린듯). https://time.pixelhize.xyz/ 사이트에 해당 코드가 적용되어 있고 소스코드는 https://github.com/PIXELHIZE/time-tool 에 있습니다. 매우 자세하게 설명 해놨으니 참고해서 코드 이해해 보세요.
// ---------------------------------------------
// 변수 선언 및 HTML 요소 가져오기
// ---------------------------------------------
// [스톱워치 관련 변수]
// 스톱워치 시작 시각 (밀리초 단위)
let stopwatchStartTime = 0;
// 스톱워치가 업데이트 될 때 계산되는 경과 시간
let stopwatchUpdatedTime = 0;
// 일시정지 후 다시 시작할 때 이전에 경과한 시간을 저장
let stopwatchDifference = 0;
// setInterval()의 ID를 저장 (스톱워치 업데이트에 사용)
let stopwatchInterval;
// 스톱워치가 실행 중인지 여부
let isStopwatchRunning = false;
// [타이머 관련 변수]
// 타이머 시작 시각 (밀리초 단위)
let timerStartTime = 0;
// 타이머 업데이트를 위한 setInterval()의 ID 저장
let timerInterval;
// 타이머가 실행 중인지 여부
let isTimerRunning = false;
// 사용자가 입력한 타이머 총 지속 시간 (밀리초 단위)
let timerDuration = 0;
// [HTML 요소 참조: 스톱워치]
// 스톱워치 시간을 표시할 요소
const stopwatchDisplay = document.getElementById('stopwatchDisplay');
// 스톱워치 시작/일시정지 버튼
const startPauseStopwatchBtn = document.getElementById('startPauseStopwatchBtn');
// 스톱워치 초기화 버튼
const resetStopwatchBtn = document.getElementById('resetStopwatchBtn');
// [HTML 요소 참조: 타이머]
// 타이머 시간을 표시할 요소
const timerDisplay = document.getElementById('timerDisplay');
// 사용자가 타이머 시간을 입력할 입력창들 (시, 분, 초)
const timerHourInput = document.getElementById('timerHourInput');
const timerMinuteInput = document.getElementById('timerMinuteInput');
const timerSecondInput = document.getElementById('timerSecondInput');
// 타이머 입력 영역 전체를 감싸는 컨테이너 (타이머 실행 시 숨김)
const timerInputContainer = document.getElementById('timerInputContainer');
// 타이머 시작/일시정지 버튼
const startPauseTimerBtn = document.getElementById('startPauseTimerBtn');
// 타이머 초기화 버튼
const resetTimerBtn = document.getElementById('resetTimerBtn');
// [HTML 요소 참조: 시계]
// 현재 시각을 표시할 시계 요소
const clockDisplay = document.getElementById('clockDisplay');
// [탭 및 헤더 관련 요소]
// 각 기능(스톱워치, 타이머, 시계) 화면의 컨테이너
const stopwatchTab = document.getElementById('stopwatch');
const timerTab = document.getElementById('timer');
const clockTab = document.getElementById('clock');
// 페이지 상단 헤더 영역과 헤더 보이기/숨기기 버튼
const header = document.getElementById('header');
const toggleHeaderBtn = document.getElementById('toggleHeaderBtn');
// ---------------------------------------------
// 탭 네비게이션 및 헤더 토글 기능
// ---------------------------------------------
// 사용자가 탭 버튼 클릭 시 해당 탭만 보이도록 설정
document.getElementById('stopwatchBtn').addEventListener('click', () => {
showTab('stopwatch'); // 스톱워치 탭 표시
});
document.getElementById('timerBtn').addEventListener('click', () => {
showTab('timer'); // 타이머 탭 표시
});
document.getElementById('clockBtn').addEventListener('click', () => {
showTab('clock'); // 시계 탭 표시
});
// 헤더 토글 버튼 클릭 시, 헤더 영역을 보이거나 숨김
toggleHeaderBtn.addEventListener('click', () => {
if (header.style.display === 'none') {
header.style.display = 'flex';
toggleHeaderBtn.textContent = 'Hide Header';
} else {
header.style.display = 'none';
toggleHeaderBtn.textContent = 'Show Header';
}
});
// showTab 함수: 전달된 탭 이름에 따라 모든 탭은 숨기고 선택한 탭만 보여줌
function showTab(tabName) {
// 모든 탭을 숨김 처리
stopwatchTab.style.display = 'none';
timerTab.style.display = 'none';
clockTab.style.display = 'none';
// 선택된 탭만 다시 보이도록 설정
if (tabName === 'stopwatch') {
stopwatchTab.style.display = 'flex';
} else if (tabName === 'timer') {
timerTab.style.display = 'flex';
} else if (tabName === 'clock') {
clockTab.style.display = 'flex';
}
}
// ---------------------------------------------
// 스톱워치 기능
// ---------------------------------------------
// startPauseStopwatch 함수: 스톱워치를 시작하거나 일시정지하는 기능
function startPauseStopwatch() {
if (!isStopwatchRunning) {
// 스톱워치가 실행 중이 아니면 시작 혹은 재시작
// 이전 일시정지 상태의 경과 시간(timerDifference)을 반영하여 시작 시간을 보정
stopwatchStartTime = new Date().getTime() - stopwatchDifference;
// 10밀리초 간격으로 updateStopwatch 함수 호출하여 화면 업데이트
stopwatchInterval = setInterval(updateStopwatch, 10);
startPauseStopwatchBtn.textContent = 'Pause'; // 버튼 텍스트 변경
isStopwatchRunning = true; // 실행 상태 업데이트
} else {
// 스톱워치가 실행 중이면 일시정지
clearInterval(stopwatchInterval); // 업데이트 멈춤
// 현재까지 경과된 시간을 저장하여 이후 재시작 시 사용
stopwatchDifference = new Date().getTime() - stopwatchStartTime;
startPauseStopwatchBtn.textContent = 'Start';
isStopwatchRunning = false;
}
}
// resetStopwatch 함수: 스톱워치 초기화(시간 리셋 및 인터벌 정리)
function resetStopwatch() {
clearInterval(stopwatchInterval); // 실행중인 타이머 정지
stopwatchStartTime = 0;
stopwatchUpdatedTime = 0;
stopwatchDifference = 0;
isStopwatchRunning = false;
// 화면에 초기 시간(00:00:00.000) 표시
stopwatchDisplay.textContent = '00:00:00.000';
startPauseStopwatchBtn.textContent = 'Start';
}
// updateStopwatch 함수: 스톱워치가 실행 중일 때 주기적으로 호출되어 경과 시간을 계산 후 갱신
function updateStopwatch() {
// 현재 시간과 시작 시간의 차이를 계산하여 경과 시간 업데이트
stopwatchUpdatedTime = new Date().getTime() - stopwatchStartTime;
// 경과 시간을 밀리초, 초, 분, 시 단위로 계산
let milliseconds = Number.parseInt((stopwatchUpdatedTime % 1000) / 10); // 10ms 단위
let seconds = Math.floor((stopwatchUpdatedTime / 1000) % 60);
let minutes = Math.floor((stopwatchUpdatedTime / (1000 * 60)) % 60);
let hours = Math.floor((stopwatchUpdatedTime / (1000 * 60 * 60)) % 24);
// 두 자리 숫자 형식으로 맞추기 위해 앞에 0 추가 (예: 5 → 05)
milliseconds = milliseconds < 10 ? `0${milliseconds}` : milliseconds;
seconds = seconds < 10 ? `0${seconds}` : seconds;
minutes = minutes < 10 ? `0${minutes}` : minutes;
hours = hours < 10 ? `0${hours}` : hours;
// 스톱워치 디스플레이에 시간 업데이트 (형식: HH:MM:SS.ms)
stopwatchDisplay.textContent = `${hours}:${minutes}:${seconds}.${milliseconds}`;
}
/* [예시: 스톱워치 사용]
- 사용자가 'Start' 버튼을 누르면 startPauseStopwatch()가 호출되어 스톱워치가 시작됩니다.
- 시간이 흐르며 stopwatchDisplay에 실시간으로 경과 시간이 "00:00:05.23"와 같이 업데이트됩니다.
- 'Pause' 버튼을 누르면 스톱워치가 일시정지되고, 다시 'Start'를 누르면 이전 경과 시간부터 재개됩니다.
- 'Reset' 버튼을 누르면 모든 값이 초기화되어 "00:00:00.000"이 표시됩니다.
*/
// ---------------------------------------------
// 타이머 기능
// ---------------------------------------------
// startPauseTimer 함수: 타이머를 시작하거나 일시정지하는 기능
function startPauseTimer() {
if (!isTimerRunning) {
// 타이머 시작 전, 사용자가 입력한 시, 분, 초 값을 읽어옴 (잘못된 입력은 0으로 처리)
const hours = Number.parseInt(timerHourInput.value) || 0;
const minutes = Number.parseInt(timerMinuteInput.value) || 0;
const seconds = Number.parseInt(timerSecondInput.value) || 0;
// 입력값을 밀리초로 변환하여 timerDuration 계산
timerDuration = (hours * 3600 + minutes * 60 + seconds) * 1000;
timerStartTime = new Date().getTime();
if (timerDuration > 0) {
// 유효한 타이머 시간일 경우, 10밀리초 간격으로 updateTimer 호출
timerInterval = setInterval(updateTimer, 10);
startPauseTimerBtn.textContent = 'Pause';
// 타이머 실행 중에는 입력창을 숨겨 사용자의 값 변경을 방지
timerInputContainer.style.display = 'none';
isTimerRunning = true;
}
} else {
// 타이머가 실행 중일 경우 일시정지: 남은 시간을 재계산 후 업데이트
clearInterval(timerInterval);
timerDuration -= (new Date().getTime() - timerStartTime);
startPauseTimerBtn.textContent = 'Start';
isTimerRunning = false;
}
}
// resetTimer 함수: 타이머 초기화 (시간 리셋, 인터벌 중지, 입력창 복원)
function resetTimer() {
clearInterval(timerInterval);
isTimerRunning = false;
// 타이머 디스플레이를 초기값으로 재설정
timerDisplay.textContent = '00:00:00.00';
startPauseTimerBtn.textContent = 'Start';
// 타이머 입력 영역을 다시 보이게 함
timerInputContainer.style.display = 'block';
}
// updateTimer 함수: 타이머가 실행 중일 때 남은 시간을 계산하여 갱신
function updateTimer() {
// 남은 시간을 계산: 설정된 시간에서 경과한 시간을 뺌
const remainingTime = timerDuration - (new Date().getTime() - timerStartTime);
if (remainingTime <= 0) {
// 남은 시간이 0 이하가 되면 타이머 종료 처리
clearInterval(timerInterval);
timerDisplay.textContent = '00:00:00.00';
isTimerRunning = false;
startPauseTimerBtn.textContent = 'Start';
timerInputContainer.style.display = 'block';
alert('Time is up!'); // 타이머 종료 알림
return;
}
// 남은 시간을 밀리초, 초, 분, 시 단위로 분해
let milliseconds = Number.parseInt((remainingTime % 1000) / 10);
let seconds = Math.floor((remainingTime / 1000) % 60);
let minutes = Math.floor((remainingTime / (1000 * 60)) % 60);
let hours = Math.floor((remainingTime / (1000 * 60 * 60)) % 24);
// 두 자리 형식 맞추기
milliseconds = milliseconds < 10 ? `0${milliseconds}` : milliseconds;
seconds = seconds < 10 ? `0${seconds}` : seconds;
minutes = minutes < 10 ? `0${minutes}` : minutes;
hours = hours < 10 ? `0${hours}` : hours;
// 타이머 디스플레이 업데이트 (형식: HH:MM:SS.ms)
timerDisplay.textContent = `${hours}:${minutes}:${seconds}.${milliseconds}`;
}
/* [예시: 타이머 사용]
- 사용자가 시, 분, 초 입력창에 예를 들어 "0", "1", "30"을 입력하면 타이머는 1분 30초로 설정됩니다.
- 'Start' 버튼을 누르면 타이머가 시작되어 남은 시간이 "00:01:30.00"에서 카운트 다운됩니다.
- 중간에 'Pause'를 누르면 일시정지되고, 다시 'Start'를 누르면 일시정지한 시점부터 계속 카운트 다운됩니다.
- 시간이 모두 경과하면 alert 창이 뜨고, 타이머는 초기 상태로 복원됩니다.
*/
// ---------------------------------------------
// 시계 기능
// ---------------------------------------------
// updateClock 함수: 현재 시간을 가져와 시계 디스플레이에 갱신
function updateClock() {
const now = new Date();
let seconds = now.getSeconds();
let minutes = now.getMinutes();
let hours = now.getHours();
// 1자리 수일 경우 앞에 0을 붙여 두자리 형식 유지
seconds = seconds < 10 ? `0${seconds}` : seconds;
minutes = minutes < 10 ? `0${minutes}` : minutes;
hours = hours < 10 ? `0${hours}` : hours;
// 시계 디스플레이에 현재 시각 표시 (형식: HH:MM:SS)
clockDisplay.textContent = `${hours}:${minutes}:${seconds}`;
}
// 시계는 1초마다 updateClock 함수를 호출해 현재 시각을 업데이트
setInterval(updateClock, 1000);
/* [예시: 시계 사용]
- 페이지에 접속하면 시계 탭에 현재 시간이 "08:07:05"와 같이 표시됩니다.
- 매 초마다 시간이 갱신되어 정확한 현재 시간을 보여줍니다.
*/
// ---------------------------------------------
// 이벤트 리스너 등록 및 초기 탭 설정
// ---------------------------------------------
// 각 버튼에 대해 클릭 이벤트를 등록하여 해당 기능을 수행하도록 함
startPauseStopwatchBtn.addEventListener('click', startPauseStopwatch);
resetStopwatchBtn.addEventListener('click', resetStopwatch);
startPauseTimerBtn.addEventListener('click', startPauseTimer);
resetTimerBtn.addEventListener('click', resetTimer);
// 페이지 로드 시 기본적으로 스톱워치 탭을 보여줌
showTab('stopwatch');
