カウントダウンタイマーの作り方。プログレスバーと残り時間の表示を実装

2023年2月25日

カウントダウンタイマー完成例

カウントダウンタイマー

開始ボタンを押すと、プログレスバーが動き、かつ、コンマ代まで数値が動くカウントダウンタイマーの実装

カウントダウンタイマー例のソースコード(関連箇所)

HTML

<div class="progBar">
  <p class="seconds js-remainTime"></p>
  <div class="bar js-remainBar"></div>
</div>
<button class="btn js-start">開始</button>

CSS

.progBar {
  background-color: rgba(255,0,0,0.5);
  border-radius: 10px;
  height: 50px;
  overflow: hidden;
  position: relative;
  width: 100%;
}
.progBar .bar {
  background-color: rgba(176,196,222,0.7);
  height: 100%;
  position: absolute;
  top: 0;
  /*初期値(カウントアップにするなら0%)*/
  width: 100%;
}
.progBar .seconds {
  line-height: 50px;
  margin: 0;
  position: relative;
  text-align: center;
  z-index: 1;
}

HTML 、CSS共に至ってシンプル。

JavaScript(jQuery)

$(function() {
  var TimerCD = (function() {
    /*========================================
    PRIVATE PROPERTY
    ========================================*/
    var timeMili = 10000;//10000ミリ秒
    var timeSec = timeMili / 1000;//10秒
    var remainTime = timeMili;
    var $time = $('.js-remainTime');
    var $bar = $('.js-remainBar');
    /*========================================
    PRIVATE METHOD
    ========================================*/
    //表示用String変換
    var conversionStr = function() {
      var strSec = String(Math.floor(remainTime/1000) % 60);
      var strMili = String(Math.floor(remainTime/10) % 100).padStart(2, '0');
      return strSec+':'+strMili;
    };
    //初期化
    var init = function() {
      remainTime = timeMili;
      $time.text(conversionStr());
      $bar.removeAttr('style');
    };

    return {
      /*========================================
      PUBLIC METHOD
      ========================================*/
      //ゲッター
      getTimeMili : function() {
        return timeMili;
      },
      getRemainTime : function() {
        return remainTime;
      },
      runInit : function() {
        init();
      },
      //カウントダウン開始メソッド
      countDown : function() {
        var date = new Date();
        var now = date.getTime();
        var targetTime = now + timeMili;

        var intervalId = setInterval(function() {
          date = new Date();
          now = date.getTime();
          remainTime = targetTime - now;
          $time.text(conversionStr());
          if(remainTime <= 0) {
            init();
            clearInterval(intervalId);
          }
        },20);
        //プログレスバーにstyle付与
        $bar.css({'transition':timeSec+'s linear','width':'0%'});
      }
    };
  })();

  //初期化
  TimerCD.runInit();
  //開始
  $('.js-start').on('click',function() {
    if(TimerCD.getRemainTime() === TimerCD.getTimeMili()) TimerCD.countDown();
  });
});

カウントダウンタイマーのjQuery解説

クロージャ、即時実行関数

オブジェクトを定義し、インスタンス生成。

 var TimerCD = (function() {
  //PRIVATE PROPERTY
  //PRIVATE METHOD

  return {
    //PUBLIC PROPERTY
    //PUBLIC METHOD

  };
})();

基本的にグローバル変数の宣言を減らしたいため、クロージャで記述。
クロージャとは「自分を囲むスコープにある変数を参照できる関数」

PUBLICの所に記述したものはインスタンス生成後、アクセスできる。
PRIVATEの所に記述したものは、外から直接アクセスできない。
PRIVATEの所に記述したものは、PUBLICの関数から参照できる。

また、こう記述することで、定義と同時にインスタンスを生成できる。

var TimerCD = (function() {
  ...
})();

クロージャ、即時実行関数についてはまた別の機会に詳しく。

本題へ。

初期表示

var TimerCD = (function() {
  ...
  return {
    ...
  };
})();
//初期化
TimerCD.runInit();
//開始
$('.js-start').on('click',function() {
  if(TimerCD.getRemainTime() === TimerCD.getTimeMili()) TimerCD.countDown();
});

初期の流れは下記の通り

  1. インスタンス生成
  2. 初期化し、タイマーの文字列を表示
  3. 開始をクリック→残り時間が初期設定時間と同じなら、カウントダウンスタート。

PRIVATE PROPERTY

//カウントダウンしたい秒数(ミリ秒で)
var timeMili = 10000; //10000ミリ秒
//秒換算
var timeSec = timeMili/1000; //10秒
//残り時間用変数定義(初期値ミリ秒)
var remainTime = timeMili;
//DOMの取得
var $time = $('.js-remainTime');
var $bar = $('.js-remainBar');

各種参照したい変数(プロパティ)を定義。参照されているのローカル変数はずっと保持される。

変数timeMiliに任意の値をミリ秒で入れると、以降は自動で換算。

PRIVATE METHOD

表示用String変換メソッド

//表示用String変換
var conversionStr = function() {
  //残りミリ秒を秒に換算し、60で剰余。その後、文字列に変換。
  var strSec = String(Math.floor(remainTime/1000) % 60);

  //残りミリ秒のうち、秒の下2桁を取得。その後、文字列に変換。
  var strMili = String(Math.floor(remainTime/10) % 100).padStart(2, '0');
  
  //文字列を「:」を付けてreturn
  return strSec+':'+strMili;
};

秒数計算の例。

var strSec = String(Math.floor(remainTime/1000) % 60);

例)「4567」なら「/1000」で「4」を取得。
今回の場合、「分」がないため60で剰余は特にいらない。
例)%60を付けて、「timeMili」を「80000」にすると、「20」から減っていき、「0」になると、「60」からまた減っていく。

var strMili = String(Math.floor(remainTime/10) % 100).padStart(2, '0');

例)「4567」なら「/10」で「456」にし、「% 100」で100で割った余りの、「56」を取得。
取得した値が1桁しかない時、「padStart(2, '0')」で「03」のように、前に「0」をつける。

初期化メソッド

//初期化
var init = function() {
  //残り時間を初期値に戻す
  remainTime = timeMili;
  //残り時間を文字列に変換した値を、text()で表示。
  $time.text(conversionStr());
  //プログレスバーのstyle属性を削除
  $bar.removeAttr('style');
};

プログレスバーのstyle属性に後述のメソッドでcssを当てていくので、初期化メソッドでstyleをリセット。

PUBLIC METHOD

ゲッター

getTimeMili : function() {
  return timeMili;
},
getRemainTime : function() {
  return remainTime;
},
runInit : function() {
  init();
},

各種プロパティは、returnすることで取り出せる。
メソッドは実行するだけでいい。
「インスタンス名.メソッド名();」と記述すると取り出せる。

カウントダウン開始メソッド

countDown : function() {
  //現在時刻の所得
  var date = new Date();
  var now = date.getTime();
  //現在時刻にカウントダウンしたい秒数(ミリ秒)をプラスし、目標時間とする
  var targetTime = now + timeMili;
  
  //20ミリ秒毎のタイマー処理
  var intervalId = setInterval(function() {
    //現在時刻の再取得
    date = new Date();
    now = date.getTime();
    //残り時間に目標時間から現在の時間を差し引いて代入
    remainTime = targetTime - now;
    //残り時間を表示
    $time.text(conversionStr());
    //残り時間が0以下なら
    if(remainTime <= 0) {
      //初期化し、タイマー停止
      init();
      clearInterval(intervalId);
    }
  },20);
  //プログレスバーにstyle付与
  //timeSec秒かけて、プログレスバーが縮んでいく。
  $bar.css({'transition':timeSec+'s linear','width':'0%'});
}

まとめ

たったこれだけの機能でも中々長くなってしまいますね。端折ったのに。

これにセッターも用意して、任意の数字を画面から入力できるようにするなんてこともできます。
また、プログレスバーではなく、円型にしたり。

やれることが無限大で、どんどんやってしまうのがプログラミングの楽しくも恐ろしい所です。

Javascript

Posted by num33