티스토리 뷰
Vue3 composition api로 타이머를 구현해보자. 기능은 크게 시작, 정지, 재시작 총 3가지가 있다. useTimer()
hook 의 형태로 정의하려고 한다.
템플릿
<template>
<div>
<p>{{ minutesLeft }}:{{ secondLeft }}</p>
<button @click="onClickStart">start</button>
<button @click="onClickEnd">end</button>
<button @click="onClickRestart">restart</button>
</div>
</template>
남은 시간을 표현하는 minutesLeft, secondLeft
가 있으며 스크립트의 computed
속성으로 정의되어있다., 버튼 3개가 있다.
스크립트 - setup 함수
<script>
export default {
setup() {
const {
minutesLeft,
secondLeft,
startTimer,
restartTimer,
endTimer,
} = useTimer(60);
const onClickStart = () => {
startTimer();
};
const onClickEnd = () => {
endTimer();
};
const onClickRestart = () => {
restartTimer();
};
return {
minutesLeft,
secondLeft,
onClickStart,
onClickEnd,
onClickRestart,
};
},
};
useTimer()
의 인자로는 타이머로 설정할 시간(초)을 넣으면 된다.
스크립트 - useTimer()
const useTimer = (time) => {
let timeLeft = ref(time); // 제한시간(time 초)
let itId = 0;
const startTimer = () => {
if (store.state.intervalId !== 0) {
// 이미 타이머가 진행중이라면 시작불가
return;
}
itId = setInterval(() => {
store.commit("setId", itId);
timeLeft.value--;
if (timeLeft.value === 0) {
endTimer();
alert("Ended");
}
}, 1000);
};
const endTimer = () => {
clearInterval(store.state.intervalId);
store.commit("setId", 0);
};
const restartTimer = () => {
endTimer();
timeLeft.value = time;
startTimer();
};
const minutesLeft = computed(() => {
return Math.floor(timeLeft.value / 60)
.toString()
.padStart(1, "0");
});
const secondLeft = computed(() => {
return Math.floor(timeLeft.value % 60)
.toString()
.padStart(2, "0");
});
return {
minutesLeft,
secondLeft,
startTimer,
endTimer,
restartTimer,
};
};
</script>
setInterval()
함수에서 1초 간격으로 timeLeft
시간을 깎고, 값이 0이 되면 endTimer
함수를 실행한 뒤에alert
가 뜬다. 이때 주의해야할 점은 setInterval
함수를 사용하므로 intervalId
값을 신경써주어야 한다. 만약 id
값을 제때 클리어하지 않을 경우에 사용자가 시작버튼을 광클했을 때 타이머가 고장나기 때문이다. 따라서 intervalId
를 단 하나만 들고있기 위해서 vuex에서 전역으로 관리한다. 그리고 endTimer
함수가 실행되면 clearInterval()
을 통해 state
에 들어있는 값을 클리어한다.
vuex - index.js
import { createStore } from "vuex";
export default createStore({
state: {
intervalId: 0
},
mutations: {
setId(state, payload) {
state.intervalId = payload;
}
},
actions: {},
modules: {}
});
'Dev' 카테고리의 다른 글
vue 에서 스크롤 위치 저장 (0) | 2023.03.09 |
---|---|
프로젝트 회고 (0) | 2023.02.18 |
vue 커스텀 디렉티브(custom directive) (0) | 2022.12.05 |
Vue3 + typescript + pinia (0) | 2022.11.12 |
css, js를 이용한 룰렛 이벤트 구현(Vue3) (0) | 2022.11.12 |
댓글