Vue.jsには監視プロパティ(Watch)という機能があります。これを使うと、ブラウザ上のインプットタグなどでユーザーが何かを入力したり、データを変更したときに、変更を検知して自動で設定した処理を走らせることができます。
ここではwatchの使い方やdeepやimmediateオプションについて実例で解説しています。
(watchのことをウォッチャーとも呼びます。)
監視プロパティ(watch)の書き方
監視プロパティはVueインスタンスの中で次のように記述します。
watch:{監視するプロパティ名: function(新しい値用の変数, 古い値用の変数){処理}}
通常は見やすくするため改行して表示することが一般的です。以下は同じ記述です。
watch:{
監視するプロパティ名: function(新しい値用の変数, 古い値用の変数){
処理
}
}
functionを省略した記述方法
上記は最も基本的なwatchの記述方法です。
ですがこの書き方以外にも、Vue.jsのmethodsやwatchなどのオブジェクトはfunctionを省略して記述することもできます。
watchでfunctionを使わない場合は以下のようになります。
watch:{
監視するプロパティ名( 新しい値用の変数, 古い値用の変数 ){
処理
}
}
: function
を省略することができます「:」も省略することに注意してください。
監視プロパティの実例
まずは、v-modelディレクティブを使って、Vue.js側とブラウザ(HTML)側の両方で双方向バインディングしたデータを作成します。
watchでそのデータを監視して、変更があった場合にconsole.logの処理を実行するプログラムを作成します。
Vue.jsのコード
Vueインスタンスの中に、データとしてプロパティ名hello、値「Hello World!」のデータを持たせます。
Watchオブジェクトの中で、上記のhelloプロパティを監視する設定にします。
helloプロパティのデータに変更があった場合、都度console.logを実行して、コンソールに元のhelloのデータと、変更後のhelloのデータを表示します。
var app = new Vue({
el:"#app",
data:{
hello: 'Hello World!'
},
watch:{
hello(newValue, oldValue){
console.log('new:', newValue, 'old:', oldValue)
}
}
})
なお、console.logは引数をカンマでつなぐことで、複数のデータをコンソールに出力することができます。
console.log('new:', newValue, 'old:', oldValue)
の場合は出力は「”new:” “Hello Worl” “old:” “Hello World”」のようになります。
HTMLコード
HTMLファイルには次の3つの要素を表示させます。
- dataオブジェクトのhelloプロパティ自体を表示。
- インプットタグでhelloプロパティの値を変更可能にする(双方向バインディング)
- dataオブジェクト自体を表示。
<body>
<div id="app">
<p>
{{ hello }}
</p>
<p>
<input type="text" v-model:value="hello">
</p>
<pre>{{ $data }}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
</body>
dataオブジェクトのhelloプロパティ自体を表示
dataオブジェクトのプロパティを表示するには開始タグと終了タグの間でマスタッシュ構文 {{ }} を使います。
{{ hello }}
インプットタグでhelloプロパティの値を変更可能にする(双方向バインディング)
Vueのデータとブラウザ上のデータを連動させるには、v-modelディレクティブを使います。
inputタグで表示されている値を双方向バインディングする場合は次のように、value属性に対してv-modelを適用し、値に結びつけるdataプロパティ名を記載します。
<input type="text" v-model:value="hello">
この設定で、デフォルトではhelloプロパティの値が表示され、変更するとVue.js側のhelloプロパティ自体のデータも書き換わるようになります。
dataオブジェクト自体を表示
Vue.jsのdataオブジェクトのデータは$data
という変数に入っています。(Vue.jsの仕様です)
ブラウザにコードを直接表示する場合はpreタグを使用します。
<pre>{{ $data }}</pre>
以上で準備は完了です。
ブラウザとコンソールの表示
ブラウザとコンソールの状態は以下のようになります。
デフォルトはブラウザ上に「Hello World!」が表示され、コンソールには何も表示されていません。
↓ 「!」と「d」の2文字を削除
inputタグの「!」と「d」の2文字を削除すると、ブラウザとコンソールの表示が次のように変わります。
inputタグの状態に合わせて、helloプロパティの値も置き変わります。コンソールを見ると、変更があった回数だけwatchが起動して、console.logを実行していることがわかります。
※ 「!」を削除したのが1回目の変更、「d」を削除したのが2回目の変更です。
↓ 「こんにちは」に置き換えると次のようになります。
実例2:距離の相互変換プログラム
watchオブジェクトの理解をより深めるために、ブラウザで入力された数値に合わせて、変更が発生する毎にkm, m, mmを自動換算するプログラムを作成します。
inputタグを3つ用意し、どれか一つの入力内容を変更すると、watchが働き、他の2つも自動で変更されます。
作成手順
- 初期値0のdataオブジェクトを用意(.js)
- inputタグを用意(.html)
- v-modelで双方向バインディング(.html)
- watchプロパティをセット(.js)
▼完成形(ブラウザ表示)
Vue.jsのコード
var app = new Vue({
el:"#app",
// 1. 初期値0のdataオブジェクトを用意
data:{
km:0,
m:0,
mm:0
},
// 4. watchプロパティをセット
watch:{
km(value){
this.km = value
this.m = value*1000
this.mm = value*1000000
},
m(value){
this.km = value/1000
this.m = value
this.mm = value*1000
},
mm(value){
this.km = value/1000000
this.m = value/1000
this.mm = value
}
}
})
HTMLファイルのコード
<body>
<div id="app">
<!-- 2. inputタグを用意(.html) -->
<p>
<!-- 3. v-modelで双方向バインディング(.html) -->
<input type="text" v-model="km">km
</p>
<p>
<input type="text" v-model="m">m
</p>
<p>
<input type="text" v-model="mm">mm
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
</body>
以上で完了です。
ブラウザでの表示
↓ mmに「1231」と入力
mmの数値を入力すると、mとkmも連動して自動計算した数値が入力されます。
実例3:フルネームを返すプログラム
watchオブジェトを使えば、ファーストネームとラストネームを入力すると、フルネームを自動計算して表示するプログラムを作成することができます。
Vue.jsのコード
var app = new Vue({
el:"#app",
data:{
firstName:'',
lastName:'',
fullName:''
},
watch:{
firstName(value){
this.fullName = value + " " + this.lastName
},
lastName(value){
this.fullName = this.lastName + " " + this.firstName
}
}
})
HTMLのコード
<body>
<div id="app">
<p>
firstName: <input type="text" v-model:value="firstName">
</p>
<p>
lastName: <input type="text" v-model:value="lastName">
</p>
<p>
fullName: {{ fullName }}
</p>
<br>
<pre>{{$data}}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
</body>
ブラウザの表示
デフォルトでは空になっています。
↓ 名前を入力
入力されたデータに合わせて、フルネームを計算して表示します。
監視プロパティのオプション
監視プロパティにはオプションが用意されています。
deepはdataオブジェクトのネストしたデータも監視する設定です。deepがない場合は、設定したプロパティ自体の変更があった場合のみしかwatchは作動しません。
immidiateは画面の初期ロード時にもwatchの処理を実行するようにするオプションです。デフォルトは初回読み込み時は処理を実行せず、変更があった場合だけwatchが作動します。
オプションがある場合とない場合の書き方の違い
オプションを設定するときは、処理をhandlerプロパティの値にする必要があります。
watch:{
監視するプロパティ名: function( 新しい値用の変数, 古い値用の変数 ){
処理
}
}
watch:{
監視するプロパティ名:{
handler: function( 新しい値用の変数, 古い値用の変数 ){
処理
},
オプション名: 真偽値
}
}
functionの有無
なお、オプションありのwatchでも、オプションが無い場合と同様に、functionを省略して記述できます。
watch:{
監視するプロパティ名: {
handler( 新しい値用の変数, 古い値用の変数 ){
処理
},
オプション名: 真偽値
}
}
handlerの後ろの: function
を省略することができます「:」も省略することに注意してください。
deepオプションの使い方実例
trueの場合、ネストされたオブジェクトも監視する設定になります。
deep = true
:ネストしたオブジェクトも監視する。deep = false
:ネストは監視しない。デフォルトの設定です。
deepオプションの実例
colorsプロパティをwatch対象にし、deep= trueのとき。colorsプロパティ配下のnameプロパティを変更したときに、console.logで変更有無を感知するプログラムを作成します。
var app1 = new Vue({
el: '#app',
data: {
colors: [
{name: 'Red'},
{name: 'Green'},
{name: 'Blue'}
]
},
//▼deepオプションありの監視プロパティ
watch: {
colors:{
handler: function(newVal, oldVal){
console.log('deepが適用されました!')
},
deep: true
}
}
})
<body>
<div id="app">
<ul>
<li v-for="color in colors">
{{ color.name }}
</li>
</ul>
<hr>
<p>(確認用)dataオブジェクト</p>
<pre>{{ $data }}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
</body>
ブラウザとコンソールの表示
コンソール上でcolorsの{name: 'Blue'}
のデータを変更すると次のようになります。
immediateオプションの使い方実例
immediateオプションを設定すると、初期読み込み時にも監視で指定した処理を実行します。デフォルトはfalseです。
immediate = ture
: 初回読み込み時に監視プロパティの処理を実行。immediate = false
: 初回は実行しない。
(deepとの併用も可能です)
immediateオプションの実例
colorsプロパティをwatch対象にし、deep= trueのとき。colorsプロパティ配下のnameプロパティを変更したときに、console.logで変更有無を感知するプログラムを作成します。
immediate: true
にするため、ページ初回読み込み時にconsole.logが実行されるようになります。
colorsプロパティをwatch対象にし、deep= trueのとき。colorsプロパティ配下のnameプロパティを変更したときに、console.logで変更有無を感知するプログラムを作成します。
var app1 = new Vue({
el: '#app',
data: {
colors: [
{name: 'Red'},
{name: 'Green'},
{name: 'Blue'}
]
},
//▼deepオプションありの監視プロパティ
watch: {
colors:{
handler: function(newVal, oldVal){
console.log('deepが適用されました!')
},
deep: true,
immediate: true
}
}
})
<body>
<div id="app">
<ul>
<li v-for="color in colors">
{{ color.name }}
</li>
</ul>
<hr>
<p>(確認用)dataオブジェクト</p>
<pre>{{ $data }}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
</body>
ブラウザとコンソールの表示
ページをロードし、何も変更を加えていない時点で、watchに記述した処理が実行されていることがわかります。