Vue.js で 配列とJSONの切り替え表示を行う

Vue.js で調べたいことがあったのでメモがてら。

## やりたいこと

Vue.jsで、ユーザーの操作に合わせてデータの増減や表示の切り替えをしたい。
テストシナリオとして、以下の3つを試してみる

* アクセスカウンタ
    * ユーザーの操作で数字が増減する
* 表示切り替え
    * ユーザーの操作で配列内のデータを切り替えて表示
* REST API のデータの表示切り替え
    * REST API経由で取得したデータを切り替えて表示


## アクセスカウンタの実装


Vue.js でアクセスカウンタを実装する方法は、[公式ドキュメント「イベントハンドリング」](https://jp.vuejs.org/v2/guide/events.html#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E8%B3%BC%E8%AA%AD)に書いている。

v-on ディレクティブを使うことで、DOM イベントの購読、イベント発火時の JavaScript の実行を行う。

以下は、簡単なアクセスカウンタの例。
[こちらの記事](https://qiita.com/ferretdayo/items/edcd2b6682148e477104)を参考にしました。 元記事では Node.js を利用していますが、今回は1枚のhtmlに書き直しています。

Vue.js はCDNから読み込んでいます。

Vue.js のインスタンス「vm」を生成。vmに変数「count」を初期値0として定義。countはリアクティブな状態にして、v-on ディレクティブで変数countに対し増減を行う。

```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Vue.js でカウンター練習</title>
  <meta charset="utf-8">
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>

<h1>Vue.js でカウンターの練習</h1>

<div id="counter">
  <div>{{count}}</div>

    <button v-on:click="decrement">-1</button>
    <button v-on:click="increment">+1</button>
</div>

<script>
  "use strict";
  const vm = new Vue({
    el: '#counter',
    data() {
      return {
        count: 0
      }
    },
    methods: {
      increment() {
        this.count++
      },
      decrement() {
        this.count--
      }
    }
  });

</script>

</body>
</html>
```

実際に動くサンプルはこちら。
https://codepen.io/TakeshiNickOsanai/pen/jXwrWL

## 配列の中身をVue.js で切り替える

さきほどのアクセスカウンタを少しアレンジ。

* 配列に格納されている文字列を「次へ」「前へ」のボタンクリックで切り替えながら表示する。
* 配列内のデータを、増減する変数「count」をキーとして取得、レンダリングする。

アクセスカウンタでは、無限に数字を増減できた。

今回のシナリオでは、配列に格納されたデータを上限として、表示のコントロールをする必要がある。そこで配列の中身をlengthで取得し、数字に上限を設けた。

同様に、0以下にはデクリメントできないように修正した。


```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Vue.js で配列の中身を切り替えながら表示する練習</title>
  <meta charset="utf-8">
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>

<h1>Vue.js で配列の中身を切り替えながら表示</h1>

<div id="counter">
  <div>{{arr[count]}}</div>

    <button v-on:click="decrement">前へ</button>
    <button v-on:click="increment">次へ</button>
</div>
  <script>

  "use strict";

   const vm = new Vue({
     el: '#counter',
     data () {
       return {
         arr : ['apple', 'orange', 'strawberry'],
         count: 0
       }
     },

  methods: {
      increment(){
        if (this.count < this.arr.length -1 ){
          this.count++;
        }
      },
      decrement() {
        if(this.count > 0) {
        this.count--
      }
    }
  }
  });
</script>

</body>
</html>
```
実際に動くサンプルはこちら

https://codepen.io/TakeshiNickOsanai/pen/bORewq


上記の例では、Vueインスタンス内のdataオブジェクトにあらかじめ配列を格納した。

下記は、先に中身が空のオブジェクト「arr」を生成。リアクティブな状態で待受を行い、あとで配列を格納する書き方。動作は上記と同じ。

```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Vue.js で配列の中身を切り替えながら表示する練習</title>
  <meta charset="utf-8">
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>

<h1>Vue.js で配列の中身を切り替えながら表示</h1>

<div id="counter">
  <div>{{arr[count]}}</div>

    <button v-on:click="decrement">前へ</button>
    <button v-on:click="increment">次へ</button>
</div>

<script>
  "use strict";
  const vm = new Vue({
    el: '#counter',
    data() {
      return {
        arr: '',
        count: 0,
      }
    },
    methods: {
      increment() {
        if (this.count < this.arr.length - 1) {
          this.count++;
        }
      },
      decrement() {
        if (this.count > 0) {
          this.count--
        }
      }
    }
  });
  // Vueインスタンス生成後、配列「arr」にデータを追加
  vm.arr = ['apple', 'orange', 'strawberry'];
</script>

</body>
</html>

```

実際に動くサンプルはこちら

https://codepen.io/TakeshiNickOsanai/pen/gZRMWM


## REST APIからデータを取得し、切り替えながら表示を行う

もう少しアレンジを加えて、以下のようなことをやってみる。

* REST APIからJSONデータを取得
    * 今回は作家「古川日出男」さんの書籍データを、Google Books APIから取得する
* 書籍データのJSONから、書籍名を配列に格納
* ユーザーの操作で、書籍名を切り替えながら表示

Google Books API から取得したJSONデータをループ処理して、タイトルだけをVMインスタンス内の配列「arr」にPUSHしていく。あとは配列のサンプルと同じ。

API経由でデータを取得してからレンダリングを行うために、Promise で非同期処理を行う。
REST APIとの通信は、axiosを使いました。

```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Vue.js でREST APIから取得したデータの切り替え練習</title>
  <meta charset="utf-8">
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>

<h1>古川日出男の著作一覧</h1>

<div id="counter">
  <div>{{arr[count]}}</div>

    <button v-on:click="decrement">前へ</button>
    <button v-on:click="increment">次へ</button>
</div>
<script>
  "use strict";
  const list = axios('https://www.googleapis.com/books/v1/volumes?q=%E5%8F%A4%E5%B7%9D%E6%97%A5%E5%87%BA%E7%94%B7');
  const vm = new Vue({
    el: '#counter',
    data() {
      return {
        arr: [],
        count: 0,
      }
    },
    methods: {
      increment() {
        if (this.count < this.arr.length - 1) {
          this.count++;
        }
      },
      decrement() {
        if (this.count > 0) {
          this.count--
        }
      }
    }
  });
  Promise.resolve(list).then(function(response) {
    for (let i in response.data.items) {
      vm.arr.push(response.data.items[i].volumeInfo.title);
    }
  });
</script>

</body>
</html>

```

動作するサンプルはこちら

https://nick-smallworld.github.io/VueJSPractice/sample-1.html