Vue.jsの続きです。前回はcomputed(算出プロパティ)で割り勘アプリを作りました。今回はwatch(監視プロパティ)で簡単なクイズを作ってみます。それではいきましょう!
【目次】
※参考:【Vue.js】computed(算出プロパティ)で割り勘アプリを作る(おまけでこち亀アプリも) - クモのようにコツコツと
戦国時代クイズを作った
watchは「監視プロパティ」と言って、何かを監視して、変化があったら処理を実行する。これを使うと、例えばこちらのような簡単なクイズを作れる。
See the Pen vue watch01 by イイダリョウ (@i_ryo) on CodePen.
クイズの答えを入力すると、正解するまでは「不正解!」というアラートが出続ける。(正解は後述します)

以前の記事でフォームに入力した内容をリアルタイムに表示した。
※参考:【Vue.js】v-modelデータバインディング事始め(リンダリンダの歌詞を変えてオリジナルラブソングを作る) - クモのようにコツコツと
今回は入力内容によって処理内容を分岐している。これを実現するのがwatch。
v-model.lazyでフォーカスアウト後に処理を実行(HTML)
コードを見ていく。まずはHTML。
<section id="quiz"> <h2>戦国時代クイズ</h2> <p>龍造寺四天王の一人で主君・龍造寺隆信から「百人並みの武勇を有する」と賞され、それにちなんだ姓を賜った武将の名前は?</p> <input v-model.lazy="input" placeholder="武将名"></input> </section>
input要素の中にv-model.lazy属性がある。このlazyは「修飾子」といって、フォームをフォーカスアウトした時(またはエンターを押したとき)に処理を実行する。(これがないと一時文字を打つごとにイベントが発火した)
修飾子は他にこんなものもある。
| 修飾子 | 詳細 |
|---|---|
| lazy | 全部書き終わってから実行 |
| number | 値を自動的に数値に変換 |
| trim | 空白を自動的に削除 |
どれもフォーム入力に使えそう!
watch以外のVue設定
次はJSのコード。
new Vue({ el: '#quiz', data: { answer: '百武賢兼', input: '' }, watch: { input: function () { const judgment = this.input.indexOf(this.answer); if (judgment >= 0) { alert('「'+ this.answer +'」正解!あなたは戦国通!!'); } else { alert('「'+ this.input +'」不正解!もう一回挑戦。') } } } });
入れ子が多いので順番に説明する。
まず全体を囲っているのがVueインスタンス。
new Vue( //処理 );
引数には連想配列が入っている。
new Vue({ el: //値, data: //値, watch: //値 });
キー名はel、dataそして今回のテーマwatch。
elキーの値は #quiz
new Vue({ el: '#quiz', data: //値, watch: //値 });
これでHTMLの#quizと紐づく。
dataの値は連想配列。キーはanswerとinput。
new Vue({ el: '#quiz', data: { answer: //値 input: //値 }, watch: //値 });
answerキーの値に答え「百武賢兼」が入っている。inputキーはHTMLのv-modelで中身は空。(ここに何か入れると初期値になる)
new Vue({ el: '#quiz', data: { answer: '百武賢兼', input: '' }, watch: //値 });
watchのJS設定
次はいよいよwatchの設定。ここだけ抜粋。watchキーの値は連想配列で、中はinputキー。
watch: { input: //処理 }
inputキーの値は無名関数。
watch: { input: function () { //処理 } }
まず変数judgmentを設定
watch: { input: function () { const judgment = this.input.indexOf(this.answer); //処理 } }
inputの入力値にanswerが含まれているかをindexOf()で判定する。indexOf()は0からのカウントで何文字目にあるかを返す。ない場合は-1を返す。
※参考:indexOfメソッド - Stringクラス - JavaScript入門
if文の条件をjudgmentが0より多い(正解)か、にする。elseには不正解のときの処理を書く
watch: { input: function () { const judgment = this.input.indexOf(this.answer); if (judgment >= 0) { //正解の値があった場合の処理 } else { //正解の値がなかった場合の処理 } } }
最後、正解、不正解の処理を書く。
watch: { input: function () { const judgment = this.input.indexOf(this.answer); if (judgment >= 0) { alert('「'+ this.answer +'」正解!あなたは戦国通!!'); } else { alert('「'+ this.input +'」不正解!もう一回挑戦。') } } }
アラートを出す。正解時はthis.answerで答えを表記。不正解時はthis.inputでフォームの入力値を表示。
で、こうなった。
See the Pen vue watch01 by イイダリョウ (@i_ryo) on CodePen.
正解を入れるとこうなる。

「百武」という姓は「百人並みの武勇」から来ているんですな。
※参考:2019/11/12追記
下記のコメントをいただきました。(Watchを使わないで実装する方法)
戦国時代クイズに関しては、watchを使用せずとも実装できそうです。
v-model.lazy -> @change
watch -> methodsカウントダウンタイマーを監視してタイマーが0になったら処理を実行するなど こういった内容は確かにwatchでないと厳しのかなと思います...
最後に
ということで、watchでインプットの値を監視して、簡単なクイズを作りましたー。

watchはフォームのバリデーションなんかにも使えそう!他にもカーソルの動きを監視したり、カウントダウンタイマーを監視してタイマーが0になったら処理を実行するなど、いろいろな使い道があるようです。
さて次回はVue.jsのアニメーションtransitionというのをやってみる予定。それではまた!
※参考:Vue.jsの習得のためにやったことまとめ
qiita.com