カウントダウンタイマーを作ろう

Javascript

こんにちはkazutoです。今回は、カウントダウンタイマーを作成していきます。

事前準備

まずは事前準備を行いましょう。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="dd.css">
  <script src="timer.js"defer></script>
</head>
<body>
<main>
  <div class="block">
    <div class="blackBox">
      <p id = "text"></p>
      <div class="msk">
        <p id="timer">00:00.000</p>
      </div>
      <button class="start" id="start">Start</button>
      <button class="reset" id="reset">Reset</button>
      <button class="up" id="up">+</button>
      <button class="down" id="down">-</button>
    </div>
      </div>
    </div>
  </div>
 
</main>
</body>
</html>

body{
  background-color: #111111;
}

main{
  height: 500px;
  width: 800px;
  margin: auto;
  margin-top: 50px;
}

.block{
  width: 500px;
  height: 500px;
  border-radius: 300px;
  background-color: black;
  margin: auto;
  position: relative;
  
}
.blackBox{
  position: absolute;
  font-size: 50px;
  text-align: center;
  top: 100px;
  bottom: 100px;
  left: 100px;
  right: 100px;
}

.timer{
  background-color: black;
  border: solid 3px #222222;
  border-radius: 10px;
  color: #66FF00;
  font-size: 50px;
}

#text{
  color: #66FF00;
  font-size: 30px;
}
button{
  border-radius: 100px;
}

.start{
  color: #66FF00;
  background-color: black;
  font-size: 30px;
  padding: 0 20px;
  margin-right: 20px
}

.reset{
  color: #66FF00;
  background-color: black;
  font-size: 30px;
  padding: 0 10px;
}

.changeColor{
  width: 100px;
  height: 100px;
  border-radius:100px ;
  background-color: black;
  position: relative;
  bottom: -29px;
  right: 6px;
}
.boderColor{
  width: 50px;
  height: 50px;
  border-radius:50px ;
  border:10px solid #66FF00;
  margin: auto;
  background-color: black ;
}

.active{
  background-color:#222222;
  color: brown;
}

.aquaColor{
  color: aqua;
}
.aquaBoder{
  border: 10px solid aqua;
}

※上記のソースコードは、必ずコピペをしてください。正しく動作しない恐れがあります。また、webフォントについて各自で設定をお願いします。
なお今回は、カウントダウンタイマー本体の実装しか解説をしません。 補助機能について解説をご覧になりたい方はこちらの記事を参照してください。

ストップウォッチを作ろう

カウントダウンタイマーを実装しよう

早速ですがカウントダウンタイマーを実装していきます。こちらのトピックでは、主に関数や変数の定義について行っていきます。

  • 変数の定義
  • 関数の定義[概念編]
  • 関数の定義[実践編]

変数の定義

まずは、必要な変数の定義を行っていきましょう。「ストップウォッチを作ろう」と同じ様な変数構成になりますが、一部変更がありますので確認をしていきましょう。

//開始時間
let startTime ;
//残り時間
let remainingTime = 0;
//経過時間
let elapsedTime = 0;
//残り時間(本体)
let timeLeft;
//setIntervalの返り値を受け取る変数
let timeId
//処理が動いているか評価
let run =false

[ストップウォッチの場合]

経過時間  =  現在時刻 - ( 開始時間  + 停止したまでの蓄積時間)

ストップウォッチの場合、

  1. 現在時刻を取得し、開始時間と停止したまでの蓄積時間の合計を現在時刻から引いて経過時間を求める
  2. 経過時間をsetIntervalを用いて10ミリ秒ごとに経過時間を更新していくことでタイマー機能を再現

という流れでタイマー機能を再現する事ができました。カウントダウンタイマーではこの一連の流れに、少し変数を追加をすれば可能になります。

続いて、カウントダウンタイマーの公式を考えてみましょう。

カウントダウンタイマー = 残り時間 ー 経過時間

となります。要するに残り時間と経過時間の差をsetIntervalを用いて10ミリ秒ごとに更新をしていくと、カウントダウンタイマーを求める事ができるという事ですね。

最終的に

経過時間  =  現在時刻 - ( 開始時間  + 停止したまでの蓄積時間)
カウントダウンタイマー = 残り時間 ー 経過時間

になりますので、手順として

  1. 経過時間を求める
  2. 残り時間と経過時間の差を求める 

を行えば、カウントダウンタイマーを再現をする事が可能になりますね。

以上で、変数定義についてのトピックを終えます。

関数の定義[概念編]

続いて、必要な関数を用意をしていきます。まずは、関数の関係性をみてみましょう。下記の画像をご覧ください。

  • Startボタンの仕組み
  • Stop&Resetボタンの仕組み
  • タイマーセット機能

[Startボタンの仕組み]

[Stop&Resetボタンの仕組み]

[タイマーセット機能]

上記、3つの画像が今回カウントダウンタイマーを実装していく上で必要な関数になります。ストップウォッチと違う点は、新たにタイマーセット機能が追加された点です。

[ストップウォッチ]

[カウントダウンタイマー]

ストップウォッチでは、Startボタンをクリックすれば、タイマーが起動したので良かったのですが、カウントダウンタイマーの場合は、名の通り時間をカウントダウンをしていきます。仕様上、デフェルトでは、時間を設定されておらず00:00.000のままです。なので、カウントダウンしていく時間を設定する必要があります。

具体的な、処理内容として

  • +ボタンがクリックされた
    →1分ごと時間をupする
  • ーボタンがクリックされた
    →1分ごと時間をdownする

となります。

以上で、関数定義[概念編]の説明を終わります。

関数の定義[実践編]

関数の定義の概念的な所の解説が終わった所で、実際にソースコードに落とし込んでいきましょう。

function InsertText(el,content){
  el.textContent = content 
}

function timeSet(sign){
  switch (sign) {
    case "+":
      remainingTime+=1000*60
      break;
    case "-":
      remainingTime-=1000*60
      break;
  }
  updateTimer(remainingTime)
}


function updateTimer(t){
  let d = new Date(t)
  let m  = d.getMinutes()
  let s  = d.getSeconds()
  let ms = d.getMilliseconds()
  m=m.toString().padStart(2,"0")
  s=s.toString().padStart(2,"0")
  ms=ms.toString().padStart(3,"0")
  timer.textContent = `${m}:${s}.${ms}`
}

function timeCountDown(){
  timerId=setInterval(function(){
    elapsedTime =new Date() -startTime
      timeLeft = remainingTime - elapsedTime
       updateTimer(timeLeft)
       if (timeLeft<=0){
        clearInterval(timerId)
        remainingTime = 0
        timeLeft= 0
        run = false
       InsertText(start,"Start")
        return updateTimer(timeLeft)
     }
    }, 10);
}



ソースコード長いので、関数ごとに解説をしていきます。

function InsertText(el,content){
  el.textContent = content 
}

こちらは、テキストを挿入をする関数です。画面に値を挿入をしたい時に使用します。

function timeSet(sign){
  switch (sign) {
    case "+":
      remainingTime+=1000*60
      break;
    case "-":
      remainingTime-=1000*60
      break;
  }
  updateTimer(remainingTime)
}

こちらのソースコードは、タイマーをセットする関数です。要するにタイマーセット機能を実現するために作成した関数です。処理内容として

  • タイマーの時間をupしたい
    →remainingTimeに60000秒(1分)を足す
  • タイマーの時間をdownしたい
    →remainingTimeに60000秒(1分)を引く

となり、再代入したremainingTimeをupdateTaimerの引数に渡し、関数を呼び出す事で、タイマーセット機能を実現をしています。

switch (sign) {
    case "+":
      remainingTime+=1000*60
      break;
    case "-":
      remainingTime-=1000*60
      break;
  }

switch文を用いて

  • sign値が文字列型の+だった場合
    →remainingTimeに60000秒(1分)を足す
  • sign値が文字列型の-だった場合
    →remainingTimeに60000秒(1分)を引く

と条件分岐をしています。

 updateTimer(remainingTime)

最終的にremainingTimeをupdateTimerの引数に渡し、呼び出します。

以上で、timeSetの解説を終わります。新たに追加した機能ですが、特に難しくは無いので、タイマーセット機能の仕組みが理解できたと思います。

続いて、updateTimerについて解説をしていきます。

function updateTimer(t){
  let d = new Date(t)
  let m  = d.getMinutes()
  let s  = d.getSeconds()
  let ms = d.getMilliseconds()
  m=m.toString().padStart(2,"0")
  s=s.toString().padStart(2,"0")
  ms=ms.toString().padStart(3,"0")
  timer.textContent = `${m}:${s}.${ms}`
}

updateTimerの処理を言語化をすると

引数のtの情報をもとに新たに時間を生成をし、その時間を

  • ミリ秒

に直し、更にゼロパディングに直し、最終的にタイマー画面に挿入をする。

という内容です。

 let d = new Date(t)
  let m = d.getMinutes()
  let s = d.getSeconds() 
  let ms= d.getMilliseconds()

上記のソースコードは、

  • d
    →引数tの情報を元に時間を生成
  • m
    →getMinutesメソッドを用いて分を取得。
  • s
    →getSecondsメソッドを用いて秒を取得
  • ms
    →getMillisecondsメソッドを用いてミリ秒を取得

と引数tの情報を元にして実装をしています。

  m = m.toString().padStart(2,`0`)
  s = s.toString().padStart(2,`0`)
  ms = ms.toString().padStart(3,`0`)

こちらは、まずtoStringメソッドを用いて、数値型から文字列型に型変換をし、その後、padStartメソッドを用いて、ゼロパディングを行っています。

ゼロパディングとは、桁数に満たない数値の場合に、足りない桁数を足して合わせる仕組みの事です。

続いて、timeCountDownについて解説をしていきます。

function timeCountDown(){
  timerId=setInterval(function(){
     elapsedTime =new Date() -startTime
      timeLeft = remainingTime - elapsedTime
       updateTimer(timeLeft)
       if (timeLeft<=0){
        clearInterval(timerId)
        remainingTime = 0
        timeLeft= 0
        run = false
       InsertText(start,"Start")
        return updateTimer(timeLeft)
     }
    }, 10);
}

timeCountDownの処理を言語化をすると、

10ミリ秒ごとにsetIntervalのコールバック関数の処理を繰り返し、残り時間から経過時間を引いた差を10ミリ秒ごとに更新をしていき、もし残り時間の値が0以下になったら変数を初期化をする

という事になります。

  elapsedTime =new Date() -startTime
   timeLeft = remainingTime - elapsedTime
   updateTimer(timeLeft)

こちらのソースコードは、先ほどの「カウントダウンタイマーの公式」をそのままコードに書き換えただけです。最終的に残り時間から経過時間を引いた差を格納している、変数timeLeftをupdateTimerの引数に渡して、呼び出し、処理結果をタイマー画面に反映します。

timerId =  setInterval(コールバック関数 , ミリ秒);

setIntervalの構文は上記の通りになります。setIntervalは、戻り値としintervalID を返します。setIntervalの繰り返し処理を止めたい場合は、intervalIDが必要になります。intervalIDとは、setInterval() を呼び出して作成したタイマーを識別する、0 ではない正の整数値です。
intervalIDを clearIntervalの引数に渡す事で、setIntervalの繰り返し処理を止める事ができます。

if (timeLeft<=0){
        clearInterval(timerId)
        remainingTime = 0
        timeLeft= 0
        run = false
        InsertText(start,"Start")
        return updateTimer(timeLeft)
     }

こちらは、if文を用いてます。残り時間から経過時間を引いた差が0以下になった場合、if文内の処理が発火し、

  • 各変数の初期化
  • setIntervalを止める
  • タイマー画面の更新
  • ボタンの更新

を行っております。

clearInterval(timerId)

こちらのソースコードは、setIntervalの繰り返し処理をclearIntervalを用いて止めています。

remainingTime = 0
timeLeft= 0

変数の値を初期化しています。

run = false
InsertText(start,"Start")
return updateTimer(timeLeft)

上から順に

変数runの値をfalseに更新し、ボタンの役割を変更。
InsertTextを用いてボタンのテキストを変更。
updateTimerを用いてタイマー画面の更新。

を行っております。

ちなみに上記のif文が無いとタイマー画面は、下記の画像の様になります。

画像をご覧いただくとわかると思うのですが、00:00.000で終わらずに、59:59.003・・・みたいに処理が続いていき、もはやカウンドダウンタイマーでは、なくなってしまいます。

なのでif文を用いて、「残り時間から経過時間を引いた差が0以下な場合」という条件分岐を行っています。

以上で、関数の定義[実践編]の解説は終わりになります。

タイマーセット機能

変数・関数の定義が終わったところで、いよいよ機能面を実装していきます。まず初めにタイマーセット機能を実装していきましょう。

  • ノードの取得
  • addEventListenerメソッドでイベント登録
  • イベントの発火後の処理を実装

ノードの取得

まずは、ノードを取得をしていきます。

function DomAcquisition(element){
  return document.querySelector(element)
  }

今回も「ストップウォッチを作ろう」で作成した「ノード取得をする関数」DomAcquisitionを使います。

function DomAcquisition(element){
  return document.querySelector(element)
  }
const timer = DomAcquisition("#timer")
const plusButton  = DomAcquisition("#up")
const minusButton = DomAcquisition("#down")

ノードを取得できているか、デバックをしてみましょう。

function forlogs(elments){
  elments.forEach(elment=>console.log(elment));
}
forlogs([plusButton,minusButton])

正しく、ノードを取得できている事が確認できたら、次にステップに進みましょう。

addEventListenerメソッドでイベント登録

ノードを取得できたら、addEventListenerメソッドを用いて、イベントを登録をしていきましょう。登録するイベントは、clickイベント使用します。

plusButton.addEventListener("click",function(){
})
minusButton.addEventListener("click",function(){
})

イベントが登録できた所で、console.logを用いてデバックをしてみましょう。

plusButton.addEventListener("click",function(){
  console.log("up");
})
minusButton.addEventListener("click",function(){
  console.log("down");
})

無事、イベントが登録できているのが確認できました。最後にイベント発火後の処理を記載していきましょう。

イベントの発火後の処理を実装

イベントが無事、登録できたので、イベント発火後の処理を実装していきましょう。

function timeSet(sign){
  switch (sign) {
    case "+":
      remainingTime+=1000*60
      break;
    case "-":
      remainingTime-=1000*60
      break;
  }
  updateTimer(remainingTime)
}


plusButton.addEventListener("click",function(){
  if(run===false){timeSet("+")}
})
minusButton.addEventListener("click",function(){
  if(run==false && remainingTime > 0 ){ timeSet("-")}
}
plusButton.addEventListener("click",function(){
  if(run===false){timeSet("+")}
})

こちらのソースコードを言語化すると、変数runの値がfalseの場合、つまり、処理が走っていない場合にtimeSetを呼び出すという事です。具体的にはsetIntervalの繰り返し処理が止まっている時です。

timeSet("+")

timesetの引数は文字列の+なので、remainingTime(残り時間)に60000秒、足します。

minusButton.addEventListener("click",function(){
  if(run==false && remainingTime > 0 ){ timeSet("-")}
}

こちらのソースコードを言語化すると変数runの値がfalseの場合、つまり、処理が走っていない且つremainingTimeの値が0を超える場合にtimeSetを呼び出すという事です。具体的には、setIntervalの繰り返し処理が止まっており、残り時間の値が0を超える場合です。

timeSet("-")

timesetの引数は文字列のーなので、remainingTime(残り時間)から60000秒、引きます。

以上で、「タイマー機能」の実装を終えます。比較的、シンプルで理解しやすかったと思います。この調子で最後まで実装していきましょう。

開始・停止・初期化機能

最後に

  • 起動
  • 停止
  • 初期化

と3つの機能を実装していきましょう。

  • ノードの取得
  • addEventListenerメソッドでイベント登録
  • イベントの発火後の処理を実装

ノードの取得

まずはノードを取得していきましょう。

const start = DomAcquisition("#start")
const reset = DomAcquisition("#reset")

ノードを取得できているか、デバックをしてみましょう。

function forlogs(elments){
  elments.forEach(elment=>console.log(elment));
}
forlogs([start,reset])

正しく、ノードを取得できている事が確認できたら、次にステップに進みましょう。

addEventListenerメソッドでイベント登録

ノードを取得できたら、addEventListenerメソッドを用いて、イベントを登録をしていきましょう。登録するイベントは、clickイベント使用します。

 start.addEventListener("click",function(){

  })

  reset.addEventListener("click",function(){

  })

イベントが登録できた所で、console.logを用いてデバックをしてみましょう。

start.addEventListener("click",function(){
    console.log("start&stop");
  })

  reset.addEventListener("click",function(){
    console.log("reset");
  })

無事、イベントが登録できているのが確認できました。最後にイベント発火後の処理を記載していきましょう。

イベントの発火後の処理を実装

イベントが無事、登録できたので、イベント発火後の処理を実装していきましょう。

start.addEventListener("click",function(){
    if(remainingTime<=0){return}
    if(run===false){
      startTime =new Date()
      timeCountDown()
      run=true
     InsertText(start,"Stop")
    }else{
     InsertText(start,"Start")
      remainingTime = timeLeft 
      clearInterval(timerId)
      updateTimer(remainingTime)
      run=false
      }
  })
  reset.addEventListener("click",function(){
    clearInterval(timerId)
    remainingTime = 0
    timeLeft = 0
    run =false
    InsertText(start,"Start")
    return updateTimer(remainingTime)
  })

ソースコードが長いので、抜粋して解説をしていきます。

start.addEventListener("click",function(){
    if(remainingTime<=0){return}
    if(run===false){
      startTime =new Date()
      timeCountDown()
      run=true
     InsertText(start,"Stop")
    }else{
     InsertText(start,"Start")
      remainingTime = timeLeft 
      clearInterval(timerId)
      updateTimer(remainingTime)
      run=false
      }
  })

こちらのソースコードは、if文を用いて

  • もし残り時間が0以下になった場合
    →何も起こらない
  • もし、処理が作動していなかった場合
    →処理を作動させる。
  • それ以外(処理が作動している場合)
    →処理を止める

と条件分岐をしています。

if(remainingTime<=0){return}

remainingTimeの値が0以下の場合はreturnメソッドを用いて処理を強制終了しています。

変数startのclickイベントの中には

  • 開始機能
  • 停止機能

と2つの機能を持っています。

2つの機能を1つのボタンで再現をするには、真偽値を使う必要があります。なので変数runを使って、条件分岐をします。

let run = false
 if(run===false){
      startTime =new Date()
      timeCountDown()
      run=true
      InsertText(start,"Stop")
    }

変数runがfalseの時は、開始機能の役割を担います。処理内容を言語化をすると、

Startボタンがクリックしてイベントが発火した且つ、変数runの値が、falseの場合は、開始した時間を取得して,変数startTimeに格納する。その後、変数runの値をtrueに変更し、ボタンの文字列をStopに変更し、timeCountDownを呼び出す

という内容です。

ポイントはrunの値をtrueに変更している点です。真偽値を変更をしないと挙動を分ける事ができないので、書き忘れに注意してください。

 }else{
      clearInterval(timerId)
      run=false
      remainingTime = timeLeft 
      InsertText(start,"Start")
      updateTimer(remainingTime)
      }
 cclearInterval(timerId)

runの値がtrueの場合は、timeCountDownのsetIntervalの繰り返し処理を止めて、時間を停止をしなければいけません。なので、clearIntervalの引数にtimerIdを渡して処理を止めます。

 run=false
 InsertText(start,"Start")

変数runの値をfalseにし、InsertTextを用いて、対象のボタンにStartと文字列を挿入しています。

 remainingTime = timeLeft 
 updateTimer(remainingTime)

残り時間から経過時間を引いた差が格納されている変数timeLeftを変数remainingTimeの中に格納し、updateTimerの引数にremainingTime渡し、関数を呼び出しています。

remainingTime = timeLeft 

変数remainingTime にtimeLeft を格納している理由は、再度、Startボタンクリックしたら、timeLeftの値が初期化してしまい、またセットした時間からカウントダウンしていってしまうからです。

function timeCountDown(){
  timerId=setInterval(function(){
    elapsedTime = new Date() -startTime
      timeLeft = remainingTime - elapsedTime
       updateTimer(timeLeft)
       if (timeLeft<=0){
        clearInterval(timerId)
        remainingTime = 0
        timeLeft= 0
        run = false
       InsertText(start,"Start")
        return updateTimer(timeLeft)
     }
    }, 10);
}
 timeLeft = remainingTime - elapsedTime

ここで注意して欲しいのは、remainingTimeの値は、変化しないという点です。あくまでも計算結果を格納している変数は、timeLeftです。したがって、remainingTimeの値は、変化をしないので、Startボタンが押された段階で、tineLeftの値の中にremainingTimeが格納をされ、timeLeftの値が初期化されてしまいます。そして、再度、セットした時間からカウントダウンしていってしまいます。

なので、リアルタイムで値が動いているtimeLeftの値をStopボタンがクリックされた瞬間にremainingTimeに引き継ぐ必要があります。

今回の「カウントダウンタイマーを作ろう」の中で一番大切なので、必ずポイントを抑えておきましょう。

続いて初期化機能を実装していきましょう。

 reset.addEventListener("click",function(){
    clearInterval(timerId)
    remainingTime = 0
    timeLeft = 0
    run =false
    InsertText(start,"Start")
    return updateTimer(remainingTime)
  })
clearInterval(timerId)

停止機能と同様、まずは、clearIntervalを用いて繰り返し処理を止めます。

 remainingTime = 0
 timeLeft = 0
  • remainingTime
  • timeLeft

の値を初期化します。

run = false
InsertText(start,`Start`)

リセットするという事は初期化するという事ですので、処理が走っている場合は、止めないとおかしな挙動になります。なので、変数runの値をfalseにして、InsertTextを用いて、ボタンをStartという文字列に変更します。

return updateTimer( remainingTime)

最後に初期化したremainingTimeをupdateTimerの引数に渡し、呼び出して終了です。

以上で「カウントダウンタイマーを作ろう」の実装を終えます。リファクタリングした、完成版のソースコードは、下記に貼り付けておきます。

※リファクタリング内容については、解説を省かせていただきます。

// 変数・定数・配列
const timer = DomAcquisition("#timer")
const start = DomAcquisition("#start")

const reset = DomAcquisition("#reset")
const plusButton  = DomAcquisition("#up")
const minusButton = DomAcquisition("#down")
const buttons =[start,reset, plusButton,minusButton]


let startTime ;
let remainingTime = 0;
let elapsedTime = 0;
let timeLeft;
let timeId;
let run =false

//関数
function forlogs(elments){
  elments.forEach(elment=>console.log(elment));
}
function DomAcquisition(element){
  return document.querySelector(element)
  }
  function classChange(element,className,num){
    switch (num){
      case 1:
        element.classList.add(className) ;
        break;
      case 2:
        element.classList.remove(className) ; ;
        break;
      case 3:
        element.classList.toggle(className) ; ;
        break;
    }
  }
function addEvent(eventTarget,eventName,callBack){
    eventTarget.addEventListener(eventName,callBack)
  }
function InsertText(el,content){
  el.textContent = content 
}
function updateTimer(t){
  let d = new Date(t)
  let m  = d.getMinutes()
  let s  = d.getSeconds()
  let ms = d.getMilliseconds()
  m=m.toString().padStart(2,"0")
  s=s.toString().padStart(2,"0")
  ms=ms.toString().padStart(3,"0")
  timer.textContent = `${m}:${s}.${ms}`
}
function timeCountDown(){
  timerId=setInterval(function(){
    elapsedTime =new Date() -startTime
      timeLeft = remainingTime - elapsedTime
       updateTimer(timeLeft)
       if (timeLeft<=0){
        clearInterval(timerId)
        remainingTime = 0
        timeLeft= 0
        run = false
       InsertText(start,"Start")
        return updateTimer(timeLeft)
     }
    }, 10);
}
function timeSet(sign){
  switch (sign) {
    case "+":
      remainingTime+=1000*60
      break;
    case "-":
      remainingTime-=1000*60
      break;
  }
  updateTimer(remainingTime)
}
function startClickEvent(){
    if(remainingTime<=0){return}
    if(run===false){
      startTime =new Date()
      timeCountDown()
      run=true
     InsertText(start,"Stop")
    }else{
     InsertText(start,"Start")
      remainingTime = timeLeft 
      console.log(remainingTime);
      clearInterval(timerId)
      updateTimer(timeLeft)
      run=false
      }
  }
  function resetClickEvent(){
    clearInterval(timerId)
    remainingTime = 0
    timeLeft = 0
    run =false
   InsertText(start,"Start")
   return updateTimer(remainingTime)
}


function plusButtonClickEvent(){
  if(run ===false){timeSet("+")}
}

function minusButtonClickEvent(){
  if(run==false && remainingTime > 0 ){ timeSet("-")}
}

 function MouseoverAndMouseleaveEvent(){ 
   classChange(this,"active",1)
   this.addEventListener("mouseleave",()=>classChange(this,"active",2))
}

function buttonsEvents(eventName){
  buttons.forEach(eventTarget=>{
  if (eventName==="mouseover") {
    addEvent(eventTarget,eventName,MouseoverAndMouseleaveEvent)
  }else{
 
  switch (eventTarget) {
    case start:
      addEvent(eventTarget,eventName,startClickEvent)
      break;
    case reset:
      addEvent(eventTarget,eventName,resetClickEvent)
    break;
    case plusButton:
      addEvent(eventTarget, eventName,plusButtonClickEvent)
    break;
    case minusButton:
      addEvent(eventTarget,eventName,minusButtonClickEvent)
    break;
    }
   }
  })
}

// 処理呼び出し
const eventNames = ["mouseover","click"]
eventNames.forEach(eventName=>{ buttonsEvents(eventName)})

まとめ:カウントダウンタイマーを作ろう

今回は、カウントダウンタイマーについて実装していきました。機能自体は、ストップウォッチとさほど、変わら無いのですが、ソースコードに置き換えてみるとかなり違いがわかると思います。
なので、作成したカウントダウンタイマーを自己流に拡張しても面白いですね。

例えば

  • アラーム機能(音声機能)
  • タイマーセット機能を変更

とかです。

※タイマーセット機能について下記の画像を参考にしてみてください。

以上、kazutoでした。

関連記事

※カウントダウンタイマーを作成するにあたりDOMの知識が必要になります。DOMについて不安要素がある方は、下記の関連記事を一通り参照してから実装をする事を推奨します。また、ストップウォッチに関しても実装内容が似ているので、参考程度に参照してください。