JavaScript
ポエム
vue.js
SemanticUI
個人開発

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

Vue.jsを勉強してみた

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

今回のアウトプット

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

以前作ったもの

Vue.jsの概要

Vue.js - TOP

Vue.jsの特徴

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

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

作ったもの

成果物

https://tech-portfolio.org/bingo_machine/
※ドラムロールとシンバルの音が流れます

成果物のイメージ

スクリーンショット 2018-06-11 8.50.34.png

使った技術

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

制作時間

6時間ほど

ビンゴマシンの仕様

  • ① 1〜75までの番号をランダムで表示する(重複はなし)
  • ② 選択された番号は下の表示欄を黄色にする
  • ③ ENTERキー押下だけで操作可能(スタート&ストップ)

ソースコード

Github - 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に慣れない部分は多々ありますが、双方向のデータバインディングはとても便利なので、今後も積極的に使っていきたいですね!