Vue.js　監視プロパティ

#Vue.js　監視プロパティ

前回の記事はこちら
[Vue.js　算出プロパティ](https://qiita.com/fumiya0414/items/964d47d2bb9bb095060f)

##監視プロパティとは
データやプロパティを監視して変化があった時に登録した処理を実行します

##監視プロパティの基本
[jsfiddle](https://jsfiddle.net/)で実際に記述しながら読むことをおすすめします。

messageプロパティのデータが変更されたら
コンソールに新旧の値を表示しましょう

以下のコードを記述します。

```html:index/html
<div id="app">

<p>
  {{ message }}
</p>

<p>
  <input type="text" v-model:value="message">
</p>

<pre>
  {{ $data }}
</pre>

</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js

var app = new Vue({
	el:'#app',
    data:{
      message:"Hello Vue.js!"
    },
  watch:{
    message:function(newValue,oldValue){
      console.log("new: %s, old: %s",newValue,oldValue)
    }
  }
})
```

dataオプションのmessageをwatchプロパティで監視して
入力で変更された値をconsole.logに出力します。
コンソールの記述はこちらを参考ください。
[[Chrome] console.log()の色々な書き方](https://qiita.com/nakajmg/items/0a27c6642268243c8eef)

実行結果は以下のとおりです。
[![Image from Gyazo](https://i.gyazo.com/76f82ade0fba9ecb015a7de496c98a98.gif)](https://gyazo.com/76f82ade0fba9ecb015a7de496c98a98)

日本語の場合は入力確定のタイミングでコンソールに結果が表示されます。

##単位変換アプリ

次にmm/m/kmを監視プロパティを使用して相互変換してみましょう

```html:index/html
<div id="app">
<p><input type="text" v-model:value="km">km</p>
<p><input type="text" v-model:value="m">m</p>
<p><input type="text" v-model:value="mm">mm</p>
</div>
<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vu"></script>
```

```javascript:index.js
var app = new Vue({
	el:'#app',
    data:{
      km:0,
      m:0,
      mm:0
    },
  watch:{
    km:function(value){
      /* console.log(value) */
      this.km = value
      this.m = value *1000
      this.mm = value *1000000
    },
    m:function(value){
      this.m = value
      this.km = value / 1000
      this.mm = value *1000 
    },
    mm:function(value){
      this.mm = value
      this.m = value /1000
      this.km = value /1000000
    }
  　}
})
```
実行結果
[![Image from Gyazo](https://i.gyazo.com/b1b55bd9868bc20b2413797e05229ee1.gif)](https://gyazo.com/b1b55bd9868bc20b2413797e05229ee1)

このようにwatchプロパティでinputの入力を監視して
km/m/mmの単位を変更することができます。

##監視プロパティと算出プロパティの比較
監視プロパティと算出プロパティは動作が似ていますので
以下のコードで検証してみましょう。

firstnameとlastnameを入力するとfullnameとして
出力されるアプリを作成します。

###監視プロパティを使用した場合

```html:index/html
<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>

</div>


<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
	el:'#app',
    data:{
      firstName:"",
      lastName:"",
      fullNAme:""
    },
  watch:{
    firstName:function(value){
      this.fullName = value +' '+ this.lastName
    },
    lastName:function(value){
      this.fullName = this.firstName +' '+ value
    }
  }
})
```
実行結果
[![Image from Gyazo](https://i.gyazo.com/a6a6fa70e535ea111f18732e97c8b660.gif)](https://gyazo.com/a6a6fa70e535ea111f18732e97c8b660)

###算出プロパティを使用した場合
```html:index/html

<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>

</div>


<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js
var app = new Vue({
	el:'#app',
    data:{
      firstName:"",
      lastName:"",
    },
  　computed:{
     fullName:function(){
       return this.firstName + " " + this.lastName
     }
   }
})
```

実行結果
[![Image from Gyazo](https://i.gyazo.com/a6a6fa70e535ea111f18732e97c8b660.gif)](https://gyazo.com/a6a6fa70e535ea111f18732e97c8b660)

いずれも動作は同じなので単純な操作の場合は
算出プロパティのコードのほうが見通しがよくなります。

期待する動作に合わせて使い分けをしましょう。

##監視プロパティのオプション

監視プロパティには以下のようなオプションをつけることができます。
deep ...ネストされたオブジェクトも監視
immediate...初期読み込み時にも呼び出し

###deepオプション
配列colorsに入れた値を変更した際に
update!と表示するプログラムを作ります。

colorsの値であるnameはネストされたオブジェクトとなります。

下記のコードで確認してみましょう

```html:index/html
<div id="app">
  <ul>
    <li v-for="color in colors">
      {{color.name}}
    </li>
  </ul>
</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js

var app = new Vue({
	el:'#app',
    data:{
      colors:[
        {name:"Red"},
        {name:"Green"},
        {name:"Blue"}
      ]
    },
    wathch:{
      colors:{
        handler:function(newValue,oldValue){
          console.log('update!')
        },
        deep: true
      }
    }
})
```

実行結果（こちらはjsfiddleではなくファイルを作って動作確認ください）
[![Image from Gyazo](https://i.gyazo.com/df341733a534f1ae24e6623df115cf9b.gif)](https://gyazo.com/df341733a534f1ae24e6623df115cf9b)

colorsにネストされたオブジェクトgreenのnameを
consoleからwhiteに変更するとupdateが表示されます。

deppオプションのデフォルト値はfalseなので
必要な時にtrueを設定しましょう。

###immediateオプション

deepオプションで使用したjsシートに以下を追記しましょう

```html:index/html
<div id="app">
  <ul>
    <li v-for="color in colors">
      {{color.name}}
    </li>
  </ul>
</div>

<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```

```javascript:index.js

var app = new Vue({
	el:'#app',
    data:{
      colors:[
        {name:"Red"},
        {name:"Green"},
        {name:"Blue"}
      ]
    },
    wathch:{
      colors:{
        handler:function(newValue,oldValue){
          console.log('update!')
        },
        deep: true,
        immediate: true  //追加
      }
    }
})
```
実行結果
[![Image from Gyazo](https://i.gyazo.com/e5b738c092b0499fba5a7e95acbecd33.png)](https://gyazo.com/e5b738c092b0499fba5a7e95acbecd33)

immediateオプションをtrueにしたことにより
ブラウザのリロード（初期読み込み）で
console.logへの出力が確認できます。

こちらも初期値はfalseなので必要に応じて設定しましょう。

次回はclassのデータバインディングです。
[Vue.js クラスとスタイルのバインディング](https://qiita.com/fumiya0414/items/af316f14d290e18fa3ba)