【JavaScript】（トイレの）音姫を作ってみた

こんにちは！Qiita初投稿の[im90](https://twitter.com/ImMikieveryday)と申します。現在、フロントエンドエンジニアを目指して勉強中です。

自分で何か作ってみるのが一番勉強になる、とよく聞くので、初めて自作アプリを作ってみました。
今回は、音姫（トイレの音なるやつ）をつくってみました。

全然大した事はしていないのですが、思い出としてこちらに残しておきたいと思います。

#実装した機能
- スタートボタンを押したら音が流れる（25秒）
- ストップボタンを押したら音が止まる
- 音が流れている間は、スタートボタンを無効にする
- ストップ → スタートの際は、改めて25秒間音を流す
- 残り時間を表示する

シンプルです:sweat_smile:　
探しましたが本物の音姫の音が無かったので、今回は波の音を使いました。
![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461266/41f6e45c-7531-1aeb-423a-a0ade65b0857.gif)
音が出るデモが無くて申し訳ないです・・・。

#コード（HTML、CSS、JavaScript）

```index.html
<body>
  <div class="container">
    <div class="contents-wrapper flex-box">
      <!-- speaker -->
      <div class="left">
        ・・・・・・・・・・・
        ・・・・・・・・・・・
        ・・・・・・・・・・・
        ・・・・・・・・・・・
        ・・・・・・・・・・・
        ・・・・・・・・・・・
        ・・・・・・・・・・・
      </div>
      <!-- ↓ display -->
      <div class="right">
        <div class="btn start" onclick="start()"><audio src="sounds/wave1.mp3" loop="true"></audio>&#8680;<br>start</div>
        <div class="btn stop" onclick="stop()">■<br>stop</div>
        <div class="remainingTime">残り秒数：<span class="lighting"></span></div>
      </div>
      <!-- ↑ display --> 

    <div class="description">
      <p>手をかざすと25秒水の流れる音がします。
        <br>途中でボタンを押すと延長します。
      </p>
    </div>
  </div>

  <footer>TOTO</footer>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="index.js"></script>
</body>
</html>
```

```style.css
*{
    margin: 0 auto;
    padding: 0;
    box-sizing: border-box;
}
body {
    margin: 3rem;
    padding: 2rem;
    width: 30rem;
    height: 20rem;
    text-align: center;
    border: .5px solid lightgrey;
    box-shadow: 1rem 1rem 1rem 1rem rgba(0, 0, 0, .4);
    user-select: none;   
}
.contents-wrapper{
    padding: 1.5rem;
    height: 10rem;
}
.left{
    width: 8rem;
    float: left;
    font-size: 10px;
    padding: 0;
}
.right{
    float: right;
    width: 13rem;
    padding: 1rem 0;
}
.btn{
    height: 3rem;
    width: 6rem;
    margin-bottom: 1rem;
    box-shadow: .1rem .1rem .1rem .1rem rgba(0, 0, 0, .4); 
    cursor: pointer;  
}
.btn:active{
    box-shadow: none;   
}
.start{
    float: left;
    background-color: black;
    color: whitesmoke;
}
.disabled{
    background-color: rgba(0, 0, 0, .8);
    pointer-events: none;
}
.stop{
    border: 1px solid lightgray;
    float: right;
}
.remainingTime{
    clear: both;
    text-align: left;
    font-size: 14px;
}
.description{
    clear: both;
}
footer{
    margin-top: 3.5rem;
}
```

```index.js
var startButton = document.querySelector('.start');
var stopButton = document.querySelector('.stop');
var light = document.querySelector('.lighting');
var audio = new Audio('sounds/wave1.mp3');
audio.loop = true;
var timeoutID;
var playing = true;

//スタートボタンを押したら音を流す
function start(){
    audio.play();
    playing = true;
    light.innerHTML = 25;
    startButton.classList.add("disabled");

    var totalTime = 25000; // 25sec
    var oldTime = Date.now();

    var timerID = setInterval(function(){        
        var currentTime = Date.now();
        var diff = currentTime - oldTime;

        var remainMsec = totalTime - diff;
        var remainSec = Math.ceil(remainMsec / 1000);
        light.innerHTML = remainSec;

        if(remainSec <= 0){
            clearInterval(timerID);
            light.innerHTML = "";
            startButton.classList.remove("disabled");
        }
        if(playing === false){
            clearInterval(timerID);
            light.innerHTML = "";
        }
    }, 1000);
    timeoutID = window.setTimeout(() => {
        audio.pause();
        audio.currentTime = 0;
    }, 25000);
}

//ストップボタンを押したら音をストップさせる
function stop(){
    audio.pause();
    clearTimeout(timeoutID);
    audio.currentTime = 0;
    playing = false;
    startButton.classList.remove("disabled");
}

```

#作成フロー（JavaScript）
1. 変数の定義
2. スタートボタンを押すと音が流れる関数をつくり、25秒でタイムアウトするようにする(`setTimeout()`)
3. ストップボタンを押すと音が止まる関数をつくる
4. 再生時はスタートボタンを無効にする（このままだとスタート関数が重複して実行できてしまうため）
5. ストップボタンを押して再生したときに、最初から音が流れる（`clearTimeout()`）この作業をしないと、ストップ → 再生したときに音が中途半端に切れてしまいました。

#作ってみて
実は今回現役プログラマーの方に見て頂いたのですが、下記のアドバイスを頂きました。

- onclickよりかは、addEventListenerを使った方が見やすい。（どの要素と関数が紐付いているかが一目で分かりやすいため）
- 現場では`==`よりも`===`を使う事が求められる。こちらの記事で分かりやすく説明されていました。[JavaScript 忘れがちな　=== と == の違い](https://qiita.com/PianoScoreJP/items/e43d70ec188c6fed73ed)

あとは、`var`でなく`let`と`const`に書き直せば良かったな～、と今更ながら思いました･･･:sweat:

また、スピーカーの見た目を再現するのに`・・・`を何個も書いたのですが、もっと良い方法があるような気もします。

お気づきの点がございましたら、もっとこうした方が良いなど、ぜひアドバイス頂けますと幸いです。

とりあえず今は次のアプリに挑戦してみようと思います！ご覧頂き、ありがとうございました。