前提
Vue.jsを使い始めて。便利だな〜と最近重宝しているのが**算出プロパティ(computed)**という仕組みです。
メソッドとは似ているようでも少し違う、computedの基本的な使い方を説明します。
算出プロパティ(computed)って何?
フォームのサンプルを使って説明します。
よくある情報登録フォームをVue.jsで作成しました。
入力される値の型チェック、未入力チェック(バリデーション)にcomputedを使っています。
実装要件
- 各項目についてバリデーションを実装し、エラーの場合はエラーメッセージ(オレンジ文字色)を各項目部分に表示
- 同じくエラーの場合は、Nextボタンを
disabled
にする - 必須項目が未入力の場合もNextボタンを
disabled
にする
computedの実行イメージ
項目をTelに絞って流れを図解してみます。
Telの入力値が数値ではなかったらエラーメッセージを表示するロジックです。
Telの入力値は、HTML側でinputタグにv-model="userInfo.tel"
と設定しているので、JS側ではthis.userInfo.tel
で参照できます。これはVue.jsのフォーム入力バインディングの仕組みですね。
やりたいことは、Tel欄の入力時にバリデーションを実行したいので、ここでcomputedの出番です。
computedの仕組みは、値が変わるとその値に依存しているすべてのバインディングが更新されます。
つまりここでは、Telの値 userInfo.tel
が変わると、それに依存しているcomputedのvalidateTel
が実行されるのです。
validateTel
の返り値をみて、HTML側でエラーメッセージを表示するかどうかをv-show
で設定しています
挙動を確認してみます。
Telの入力欄に入力する度にvalidateTel
が実行されているのがわかるかと思います!
実装を見てみる
ソースはこちら。(Ruby on Railsで環境を作っているためerbファイルを使っています)
<div id="app" class="container">
<h1>Form Example</h1>
<div class="form-group">
<label>Email [必須]</label>
<input v-model="userInfo.email" type="email" class="form-control" placeholder="例) sample@example.com">
<span v-show="!validateEmail" class="text-warning">正しいEmailを入力してください</span>
</div>
<div class="form-group">
<label>Tel [必須]</label>
<input v-model="userInfo.tel" type="text" class="form-control" placeholder="例) 0311112222">
<span v-show="!validateTel" class="text-warning">Telは数値で入力してください</span>
</div>
<div class="form-group">
<label>ユーザー名</label>
<input v-model="userInfo.userName" type="text" class="form-control" placeholder="例) user-1">
<span v-show="!validateUserName" class="text-warning">ユーザー名は半角英数字で入力してください</span>
</div>
<button :disabled="!validation" type="button" class="btn btn-info">Next</button>
</div>
$(function () {
new Vue({
el: '#app',
data: {
userInfo: {
email: '',
tel: '',
userName: ''
}
},
computed: {
validation: function () {
return (this.validateTel &&
this.validateEmail &&
this.validateUserName);
},
validateTel: function () {
var pattern = /^\d+$/; // 1文字以上の整数のみ許容
return pattern.test(this.userInfo.tel.trim());
},
validateEmail: function () {
var pattern = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return pattern.test(this.userInfo.email);
},
validateUserName: function () {
if (this.userInfo.userName.length === 0) {
return true;
} else {
var pattern = /^\w+$/; // 大文字小文字英数字、アンダースコアのみ許容
return pattern.test(this.userInfo.userName);
}
}
}
});
});
各項目のバリデーション用にcomputedを使い validateEmail
, validateTel
, validateUserName
を定義しています。
全項目のバリデーション用にそれらの返り値を返すだけのvalidation
を定義しています。
このvalidation
を使ってHTML側ではNextボタンのdisabled
を有効にするかどうかを判定しています。
computedの使いどころって?
今回の例の他にインクリメンタルサーチ(こうゆうもの)もcomputedを使えば簡単にできるみたいです!
使いどころとしては、ユーザーからのイベント発生 => 値が変更される => その値に変更があった場合、動的に何かしらの処理を実行したい 時に使えるのではと理解しています。
算出プロパティとメソッドはどう違うの?
少し余談になりますが、computedと似たようなプロパティとしてメソッド(methods)があります。
両者の違いについては公式ガイドの算出プロパティvsメソッドがわかりやすいです。
** 以下引用 **
算出プロパティの代わりに、同じような関数をメソッドとして定義することも可能です。
最終的には、2つのアプローチは完全に同じ結果になります。
しかしながら、算出プロパティは依存関係にもとづきキャッシュされるという違いがあります。
算出プロパティは、それが依存するものが更新されたときにだけ再評価されます。
** 中略 **
対称的に、メソッド呼び出しは、再描画が起きると常に関数を実行します。
** 中略 **
キャッシングしたくない場合は、代わりにメソッドを使いましょう。
メソッドを使っても同じことができそうなので、先ほどのサンプルを編集してみます。
Telのバリデーション部分のみメソッドを使う形に実装してみました。
<!-- 上記部分省略 -->
<div class="form-group">
<label>Tel [必須]</label>
<input v-model="userInfo.tel" @input="validateTel2" type="text" class="form-control" placeholder="例) 0311112222">
<span v-show="!validateTel2()" class="text-warning">Telは数値で入力してください</span>
</div>
<!-- 以下省略 -->
<!-- 上記部分省略 -->
computed: {
// ここは変更なし
},
methods: {
validateTel2: function () {
var pattern = /^\d+$/; // 1文字以上の整数のみ許容
return pattern.test(this.userInfo.tel.trim());
}
}
<!-- 以下省略 -->
JS側にメソッドvalidateTel2
を定義し、Telのinputタグに@inputを追加しました。ユーザーがinput
する度にメソッドを実行するという実装にしました。
動作しますが、このままでは他の項目(Email等)のinput
タグに入力する際もこのメソッドが実行されてしまいます。。(ノ∀`*)アチャー
もう少し工夫すれば実装できそうな気もしますが、それを探るよりもcomputedを使ってサクッと実装したほうがベターですね。
まとめ
- 算出プロパティは依存関係にもとづきキャッシュされるので、依存するものが更新される時のみ実行される。無駄な実行がない。
- 簡潔に記載できるので、可読性が高い。
賢いcomputedを使って、さらにVue.jsを楽しみましょう ^^!