Edited at

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

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


やりたいこと

Vue.jsで、ユーザーの操作に合わせてデータの増減や表示の切り替えをしたい。

テストシナリオとして、以下の3つを試してみる


  • アクセスカウンタ


    • ユーザーの操作で数字が増減する



  • 表示切り替え


    • ユーザーの操作で配列内のデータを切り替えて表示



  • REST API のデータの表示切り替え


    • REST API経由で取得したデータを切り替えて表示




アクセスカウンタの実装

Vue.js でアクセスカウンタを実装する方法は、公式ドキュメント「イベントハンドリング」に書いている。

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

以下は、簡単なアクセスカウンタの例。

こちらの記事を参考にしました。 元記事では Node.js を利用していますが、今回は1枚のhtmlに書き直しています。

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

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

<!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以下にはデクリメントできないように修正した。

<!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」を生成。リアクティブな状態で待受を行い、あとで配列を格納する書き方。動作は上記と同じ。

<!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を使いました。

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