티스토리 뷰

Dev

Vue3 타이머 구현

hjhj97 2022. 11. 12. 18:57

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
댓글