【初心者向け】Vue.jsの基礎を使って簡単にタイピングゲームを作ってみる

Vue.jsタイピングゲーム プログラミング

Javascriptのフレームワークの一つであるVue.jsを使ったタイピングゲームの作り方をご紹介します。Vue.jsの基礎の学習を終えた方は、自分で簡易アプリを作ってみるなど、学習したことをアウトプットすることで、よりスキルが定着するかと思います。

今回の記事では第一歩として、タイピングゲームの実装方法・コード解説をします。Vue.jsの代表的なディレクティブを使用していますので、ご参考になればと思います。

この記事を読んでほしい方
  • Vue.jsの基礎学習が終わった方
  • 未経験からフロントサイドエンジニアを目指す方

タイピングゲームの実装例

  • スタートボタンを押すと問題が表示され、カーソルが入力欄にフォーカスします
  • 問題は果物の名前を5問設定し、正解した場合に次の問題に進みます。
  • 正解数とともに、下のゲージが増えていきます。
  • 全問正解でクリア画面になります。

See the Pen Untitled by Yoshiki (@Yoshiki-0328) on CodePen.

コードの解説

HTMLのコード解説

スタートボタンや問題文、回答欄、正答ゲージなどをマークアップしていきます。また、Vue.jsをマウントするエリアを<div id=”app”>で指定します今回はCDNを使ってます

    <div id="app">
      <div class="title">
        <h1>Typing Game</h1>
      </div>
      <!-- スタートボタン表示・非表示 -->
      <button class="start_btn" @click="start_clicked" v-if="!start_flag">START</button>
      <div v-else>
        <!-- 問題文と回答欄を表示 -->
        <div v-if="!clear">
          <p class="question">{{questions[quesiton_num]}}</p>
          <input id="typeForm" type="text" class="answer" v-model="answer"/>
        </div>
        <div class="clear_wrapper" v-else>
          <p class="clear">CLEAR</p>
        </div>
        <!-- 正答ゲージ -->
        <div class="gage_wrapper">
          <div class="gage" :style="styleObj"></div>
        </div>
        <p class="question_number">{{quesiton_num}}/5</p>
      </div>
    </div>
<!-- 2.CDNを読み込む -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="main.js"></script>

各パートの解説

<!-- スタートボタン表示・非表示 -->
<button class="start_btn" @click="start_clicked" v-if="!start_flag">START</button>
  • :clickで、Vue.jsのv-onディレクティブで、start_clickedメソッドを実行します。
  • v-ifで、strat_flagがfalseの時だけ、ボタンを表示します。
      <div v-else>
        <!-- 問題文と回答欄を表示 -->
        <div v-if="!clear">
          <p class="question">{{questions[quesiton_num]}}</p>
          <input id="typeForm" type="text" class="answer" v-model="answer"/>
        </div>
        <div class="clear_wrapper" v-else>
          <p class="clear">CLEAR</p>
        </div>
  • v-elsestart_flagがtrueの時に問題文を表示します。
  • Clearがfalseの時だけ、問題文と回答欄を表示します。Clearフラグがtrueの時にクリアメッセージを表示します。
        <!-- 正答ゲージ -->
        <div class="gage_wrapper">
          <div class="gage" :style="styleObj"></div>
        </div>
        <p class="question_number">{{quesiton_num}}/5</p>
      </div>
  • <div class=”gage_wrapper”>で、ゲージのアウトライン(外枠)を作ります。
  • :styleで、Vue.jsのv-onディレクティブでスタイルをstyleObjにデータバインディングします。
<!-- 2.CDNを読み込む -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="main.js"></script>
  • 最後に、Vue.jsのCDNの記述と、そのあとにJavascriptファイルを読み込みます。

CSSのコード解説

メインはHTMLとJavascriptファイルになりますので、CSSはさらっといきたいと思います。

ポイントは、正答ゲージの箇所になります。こちらのCSSでは、ゲージの外枠と中身の色付きの部分の高さなどを設定していきます。正答ごとのゲージの動きはVue.js側で設定します。

*{
    font-size: 100%;
}
body{
    width: 50%;
    margin: 0 auto;
    text-align: center;
    font-size: 1.75rem;
}
h1{
    font-size: 2.5rem;
    position: relative;
    display: inline-block;
    z-index: 10;
}
h1::before{
    content: '';
    height: 10px;
    width: 100%;
    background-color: aquamarine;
    position: absolute;
    bottom: 10px;
    left: 0;
    z-index: -10;
}
.start_btn{
    background-color:grey;
    color: white;
    border-radius: 5px;
    border: none;
    outline: none;
    cursor: pointer;
    padding: 5px;
}
.start_btn:hover{
    opacity: .7;
}

.clear{
    font-size: 1.75rem;
    background-color: rgb(0, 174, 255);
    color: white;
    display: inline-block;
    border-radius: 5px;
    border: none;
    outline: none;
    padding: 5px;
}
.answer{
    text-align: center;
    border: none;
    outline: none;
    border-bottom: 1px solid grey;
    margin-bottom: 20px;
}
.gage_wrapper{
    height: 12px;
    border: 1px solid grey;
}
.gage{
    height: 12px;
    transition: .5s;
}

Javascriptのコード解説

const app = Vue.createApp({
    data(){
        return{
            start_flag:false, //開始フラグ
            questions:['apple','banana','orange','grape','strawberry'],//問題データ
            quesiton_num:0, //問題番号 
            clear:false, //クリアフラグ
            answer:"" //入力文(データバインディング)
        }
    },
    computed:{
        styleObj(){
            // 問題の正解数に応じて、ゲージのスタイルを設定する
            width = 20 * this.quesiton_num +'%'
            if(this.quesiton_num == this.questions.length){
                color = "aqua"
            }else{
                color = "orange"
            }
            return {
                "width":width,
                "background-color":color
            }
        }
    },
    methods:{
        start_clicked(){
            // スタートフラグを真にして、カーソルを入力欄にフォーカスする
            this.start_flag=true
            this.$nextTick(function(){
                document.getElementById('typeForm').focus();
            })
        }
    },
    watch:{
        answer(){
            // 問題と入力文を比較する
            if(this.questions[this.quesiton_num]==this.answer){
                this.answer=''
                this.quesiton_num++
                // 全問正解でクリアフラグを立てる
                if(this.quesiton_num==this.questions.length){
                    this.clear=true;
                }
            }
        }
    }
})
app.mount('#app');

各パートの解説

    data(){
        return{
            start_flag:false, //開始フラグ
            questions:['apple','banana','orange','grape','strawberry'],//問題データ
            quesiton_num:0, //問題番号 
            clear:false, //クリアフラグ
            answer:"" //入力文(データバインディング)
        }
    },
  • 問題データ、問題文やクリアメッセージの表示・非表示フラグなど必要なデータ要素を定義しておきます。
    computed:{
        styleObj(){
            // 問題の正解数に応じて、ゲージのスタイルを設定する
            width = 20 * this.quesiton_num +'%'
            if(this.quesiton_num == this.questions.length){
                color = "aqua"
            }else{
                color = "orange"
            }
            return {
                "width":width,
                "background-color":color
            }
        }
    }
  • styleObjのcomputedで、question_num(問題数)に応じて、widthでゲージの幅、Colorでゲージの色をスタイルします。Returnで、styleObjにwidthとcolorのスタイルを定義したものを返します。
  • Computedでは、dataなどから値を読み込み再計算、処理した値を定義することができます。
  • thisでは、Vue.js内で記述した値を呼び出す際に使用します。
    methods:{
        start_clicked(){
            // スタートフラグを真にして、カーソルを入力欄にフォーカスする
            this.start_flag=true
            this.$nextTick(function(){
                document.getElementById('typeForm').focus();
            })
        }
    },
  • start_clickedメソッドが呼ばれると、start_flag(開始フラグ)がtrueになった後、$nextTickのコールバック関数でtypeform(回答欄)にカーソルをフォーカスさせます。

$nextTickは、DOMの更新を待ってから実行されること定義します。上記の場合、開始フラグがtrueになり、回答欄が表示された後に実行される関数になります。

    watch:{
        answer(){
            // 問題と入力文を比較する
            if(this.questions[this.quesiton_num]==this.answer){
                this.answer=''
                this.quesiton_num++
                // 全問正解でクリアフラグを立てる
                if(this.quesiton_num==this.questions.length){
                    this.clear=true;
                }
            }
        }
    }
  • questions配列の問題とanswer(入力文)が一致しているかを比較して、一致した場合(正解)は、回答欄を空にして、次の問題を表示します。問題番号(正解数)と問題データの配列の長さが一致した場合は、クリアフラグをtrueにします。

まとめ

今回の記事では、Vue.jsを学習している方向けにアウトプット、手を動かす機会として、タイピングゲームの実装方法を解説しました。CDNで基礎的なVue.jsのディレクティブを使った方法となりますが、手を動かすことで、スキルの定着につながりますので徐々に複雑なアプリ開発に進んでいくなどチャレンジしてみてください。

タイトルとURLをコピーしました