結婚式の二次会用のビンゴマシンをVue.jsで作り直した

## **Vue.jsを勉強してみた**

仕事で今月から開発のフェーズに入り、フロントエンドをVue.jsのフレームワークで開発することになりました。脱JQuery、そしてMVVMの考え方に慣れるために、勉強したことのアウトプットをQiitaにまとめておきます。

* **やってみた**
    * [ドットインストール - Vue.js入門](https://dotinstall.com/lessons/basic_vuejs_v2)

* **読んでみた**
    * [基礎から学ぶ Vue.js](https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6-Vue-js-mio/dp/4863542453/ref=sr_1_1?ie=UTF8&qid=1528672573&sr=8-1&keywords=vue)

    * [Vue.jsから手軽に始めるJavaScriptフレームワーク](https://qiita.com/icoxfog417/items/49f7301be502bc2ad897) - @icoxfog417 :bow:

### **今回のアウトプット**

来週友人の結婚式がありビンゴ係に任命されているため昔作ったビンゴマシーンをVue.jsで新たに作り直しました。ソースについてはGithub上で公開しているので、ぜひ動かしてみてください！（マサカリも歓迎です:bow:）

[以前作ったもの](https://the-bingo.jp)

## **Vue.jsの概要**

[**Vue.js - TOP**](https://jp.vuejs.org/index.html)

### **Vue.jsの特徴**
Vue.jsは、双方向データバインディングができるというのが大きな特徴で、データを更新したら画面(UI)が更新される。画面（UI）が更新されたらデータが更新されるというような、シングルページアプリケーションにとても相性がいいと思います。

画面から非同期でサーバにリクエストを送り、取得したデータで必要な箇所のみをバインディングして描画することで、速いアプリケーションを構築することが可能になります。


## **作ったもの**

### **成果物**

[https://the-bingo.jp](https://the-bingo.jp)
※ドラムロールとシンバルの音が流れます

### **成果物のイメージ**
<img width="1269" alt="スクリーンショット 2018-06-11 8.50.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/147291/6e69e3c4-e6a4-438c-f1a5-f4a32610ef8f.png">

### **使った技術**

* Vue.js
* JQuery
* SemanticUI - CSSフレームワーク 

### **制作時間**

6時間ほど

### **ビンゴマシンの仕様**
* ① 1〜75までの番号をランダムで表示する（重複はなし）
* ② 選択された番号は下の表示欄を黄色にする
* ③ ENTERキー押下だけで操作可能（スタート&ストップ）

### ソースコード

[**Github - vue-bingo_machine**](https://github.com/FujiyamaYuta/vue-bingo_machine)

``` index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <title>ビンゴマシン</title>
  <link rel="stylesheet" type="text/css" href="assets/semantic/semantic.css">
  <link href="assets/css/style.css" rel="stylesheet" type="text/css">
  <script src="https://code.jquery.com/jquery-3.3.1.slim.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
  <container id="app">
    <div>
      <div class="panel" id="panel1">︎{{panel1}}</div>
      <div class="panel" id="panel10">{{panel10}}</div>
    </div>

    <div class="ui centered grid">
      <div class="two wide tablet computer  center aligned padded column">
        <button id="stopButton" v-model="stopButton" v-disable="stopButton" v-on:click="runStop()" class="ui fluid big blue button">STOP</button>
      </div>
    </div>

    <div class="ui centered grid">
      <div class="five wide tablet computer  center aligned padded column">
        <button id="spinButton" v-model="spinButton" v-disable="spinButton" class="ui fluid red button" v-on:click="runSlot()">SPIN</button>  
      </div>
    </div>

    <div class="ui centered grid">
      <div class="nine wide tablet computer  center aligned padded column">
        <div class="container">
          <div class="bingo" v-bind:style="pStyle" v-bind:id="item" v-for="item in items">
            {{ item }}
          </div>
        </div>
      </div>
    </div>

    </div>

    <div></br></br>
        <div class="copy">By <a href="https://twitter.com/Fujiyama_Yuta">＠Fujiwara_Yuta</a>, Thanks to @Ishi </div>
    </div>
  </container>
</body>
<audio id="audio_drum" src="assets/audio/drumroll.wav"></audio>
<audio id="audio_cymbal" src="assets/audio/cymbal.wav"></audio>
<script type="text/javascript" src="assets/js/bingo.js"></script>
</html>

```

```bingo.js

(function() {
    'use strict';

    var slotTimer;
    var drumRoll = document.getElementById('audio_drum');
    var cymbal = document.getElementById('audio_cymbal');
    var bingoNumArray = Array.from(new Array(75)).map((v, i) => i+1)
    var bingoNumer = "0";
    var setNum = "0";


    var vm = new Vue({
        el: '#app',
        data: {
            items: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12','13','14','15',
                    '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30',
                    '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45',
                    '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60',
                    '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75',],
            panel1:"0",
            panel10:"0",
            spinButton:false,
            stopButton: true,
            pStyle:"",
            bingoId:"0"
        },
        methods: {
            runSlot: function () {

                drumRoll.play();
                cymbal.pause();
                this.spinButton = true;
                this.stopButton = false;

                var bingoNum = bingoNumArray.length;
                if (bingoNum==0){
                    return;
                }

                bingoNumer = Math.floor(Math.random() * bingoNum).toString();
                setNum = bingoNumArray[bingoNumer];
                if (parseInt(setNum) < 10){
                    setNum = '0' + setNum;
                }
                setNum = setNum.toString();

                this.panel1 = setNum.substr(0, 1);
                this.panel10 = setNum.substr(1, 2); 

                slotTimer = setTimeout(this.runSlot, 25);

            },

            runStop: function () {
                clearInterval(slotTimer);
                cymbal.play();
                drumRoll.pause();
                this.spinButton = false;
                this.stopButton = true;
                cymbal.currentTime = 0;
                drumRoll.currentTime = 0;

                bingoNumArray.splice(parseInt(bingoNumer),1);
                var id = setNum;

                $('#' + id).addClass("unmatched");
            }

        },
        directives: {
            disable: function (el, binding) {
                el.disabled = binding.value
            }
        }
    });

    $("body").keypress(function (event) {
        if (event.which === 13) {
            console.log("ENTER");
            $('#spinButton').click();
            $('#stopButton').click();
        }
    });

})();
```

## **まとめ**

開発ではずっとJQueryを使っていたため、Vue.jsのMVVMに慣れない部分は多々ありますが、双方向のデータバインディングはとても便利なので、今後も積極的に使っていきたいですね！