JSFiddle - React, Tailwind, and code Playground

by cedric_tarou

HTML

<script src="//code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<script src="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="css/styles.css">
    <title>My Timer</title>
  </head>

  <body>
    <div class="container">
      <div id="timer">00:00.000</div>
      <div class="controles">
        <div class="btn-square-shadow" id="start">START</div>
        <div class="btn-square-shadow" id="stop">STOP</div>
        <div class="btn-square-shadow" id="reset">RESET</div>
      </div>
    </div>



    <script src="js/main.js"></script>
  </body>

</html>

CSS

body {
  font-family: sans-serif;
  font-size: 14px;
  background: #eee;
}

.container {
  width: 270px;
  /* height: 200px; */
  margin: 20px auto;
  background: #fff;
  padding: 15px;
  text-align: center;
}

#timer {
  background: #ddd;
  height: 120px;
  line-height: 120px;
  font-size: 40px;
  margin-bottom: 15px;
}

.btn-square-shadow {
  display: inline-block;
  padding: 0.5em 1em;
  text-decoration: none;
  background: #668ad8;
  /*ボタン色*/
  color: #FFF;
  border-bottom: solid 4px #627295;
  border-radius: 3px;
}

.btn-square-shadow:active {
  /*ボタンを押したとき*/
  -webkit-transform: translateY(4px);
  transform: translateY(4px);
  /*下に動く*/
  box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);
  /*影を小さく*/
  border-bottom: none;
}

.controles {
  display: flex;
  justify-content: space-between;
}

.inactive {
  opacity: 0.6;
}

JavaScript

'use strict'; {
  const timer = document.getElementById('timer');
  const start = document.getElementById('start');
  const stop = document.getElementById('stop');
  const reset = document.getElementById('reset');

  let startTime;
  let timeoutId;
  let elapsedTime = 0;

  function countUp() {
    // console.log(Date.now()-startTime);
    const d = new Date(Date.now() - startTime + elapsedTime); //日付の表示を変更するのがnew Date()
    const m = d.getMinutes();
    const s = d.getSeconds();
    const ms = d.getMilliseconds();
    timer.textContent = `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}:${String(ms).padStart(3, '0')}`;
    timeoutId = setTimeout(() => {
      countUp(); //setTimeoutの返り値をtimeoutIdに渡す

    }, 10);
  }

  function setBtnStateInitial() {
    start.classList.remove('inactive');
    stop.classList.add('inactive');
    reset.classList.add('inactive');
  }

  function setBtnStateRunning() {
    start.classList.add('inactive');
    stop.classList.remove('inactive');
    reset.classList.add('inactive');
  }

  function setBtnStateStoped() {
    start.classList.remove('inactive');
    stop.classList.add('inactive');
    reset.classList.remove('inactive');
  }


  setBtnStateInitial();
  start.addEventListener('click', () => {
    if (start.classList.contains('inactive') === true) {
      return;
    }
    setBtnStateRunning();
    startTime = Date.now();
    countUp();
  });
  stop.addEventListener('click', () => {
    if (stop.classList.contains('inactive') === true) {
      return;
    }
    setBtnStateStoped();
    clearTimeout(timeoutId); //setTimeoutを止める
    elapsedTime += Date.now() - startTime;
  });
  reset.addEventListener('click', () => {
    if (reset.classList.contains('inactive') === true) {
      return;
    }
    setBtnStateInitial();
    timer.textContent = '00:00.000';
    elapsedTime = 0;
  });

}