[Vue.js]さまざまな形のデータをv-forで展開、v-bindで渡す方法[v-for, v-bind]

Vue.jsの記事_v- forとv-bindについて

このところ、Vuetify関連の記事を続けて書いてきましたが、今回はVue.jsの基本的なディレクティブのひとつ、 v-for によるdataの展開について触れていきたいと思います。

v-forで囲まれた要素を指定回数分、繰り返す

まず、シンプルな例です。v-for の基本的な性質を知るには、まずこの例から理解すると良いかもしれません。

<template>
  <v-sheet>
    <v-slide-group multiple show-arrows>
      <v-slide-item v-for="n in 8" :key="n">
        <v-card style="margin: 0 20px 0 0; width: 320px; height: 240px;">
          <v-img class="white--text align-end" height="120px" src="********.png">
          <v-card-title>sample title {{ n }}</v-card-title>
          <v-card-text class="text--primary">
           {{ n }}番目のカードテキスト
          </v-card-text>
        </v-card>
      <v-slide-item>
    </v-slide-group>
  </v-sheet>
</template>

上記は、当サイトの記事のひとつ、
[Vue.js]Vuetifyを使ってスライダーとカルーセルを実装する方法[v-slide, v-carousel]
に掲載してある例です。

この例では、4行目に n in 8 という条件を指定していますが、
これは v-for で囲まれた要素を、
指定した回数分だけ、繰り返す、という指定になります。



この例の7行目の
sample title {{ n }}

9行目の
{{ n }}番目のカードテキスト

と指定してある箇所には、それぞれ繰り返しの回数が代入されます。
上記のコードは、v-cardコンポーネントを使って8枚のカードを並べる、
という記述ですので、
1回目の繰り返しの際には
7行目に相当する部分に
sample title 1
と表示され、

9行目に相当する部分には
1番目のカードテキスト

と表示される、
というわけです。

また、この例の様に
{{}} で囲む構文のことを Mustache(マスタッシュ)構文 と呼びます。
Vue.js公式の、次のページの最初の方に解説があります。
テンプレート構文

対象の配列(またはオブジェクト)から値を取り出す

<template>
  <v-expansion-panels>
    <v-expansion-panel
      v-for="list in lists"
      :key="list.id"
    >
      <v-expansion-panel-header>
        {{ list.title }}
      </v-expansion-panel-header>
      <v-expansion-panel-content>
        {{ list.text }}
      </v-expansion-panel-content>
    </v-expansion-panel>
  </v-expansion-panels>
</template>

上記は、当サイトの記事
[Vue.js]Vuetifyでアコーディオン型のリストを実装する方法[v-expansion-panel]
に掲載されている例です。
(Vuetify の v-expansion-panels, v-expansion-panel を組み合わせて、
v-for でリストを作っている例です。)

実際の制作では、
このタイプのdata展開方法を使用するケースが多くなると思われます。
8行目で {{ list.title }}
11行目で {{ list.text }}
と指定している様に、
v-for の中で {{}}, Mustache(マスタッシュ)構文を用いると、
dataを展開することができます。
4行目で指定している
v-for=”list in lists”
は、ざっくり言うと
list という引数を指定して、対象の lists という data に、存在する値の数だけ
v-for で囲まれた範囲を繰り返し実行する、

という記述になります。

この例の様に、v-forの繰り返し(ループ)の中では、
引数.値のキー名
と指定すると対象の値にアクセスすることが可能で、それを書いてあるのが
8行目の {{ list.title }}
11行目の {{ list.text }}

ということになります。

表示させたいdataが、以下の様なdataだった場合、
5件の値をもっているため、
v-forによって5回処理が繰り返され、
結果として、5個のリストを持ったアコーディオン型のリストが生成される、というわけです。

<script>
  new Vue({
    el: '#app',
    vuetify: new Vuetify(),
    data: {
      lists: [
          {id: 01, title: 'タイトル01',  text: 'リストの内容01'},
          {id: 02, title: 'タイトル02',  text: 'リストの内容02'},
          {id: 03, title: 'タイトル03',  text: 'リストの内容03'},
          {id: 04, title: 'タイトル04',  text: 'リストの内容04'},
          {id: 05, title: 'タイトル05',  text: 'リストの内容05'}
        ]
      }
    })
</script>

次のリンク先から、この例と同じ仕組みで実際に動いているアコーディオン型のリスト(※厳密には、Vuetifyではエキスパンションパネルと呼ばれるもの)を確認いただけます。

Vuetifyのサンプル_エキスパンションパネルを使用してみる

v-bindで値を属性に渡す。(htmlの属性にdataを渡したい場合に使えます。取得したデータをURL末尾にパラメータとして入れる、class名として渡すなど)

今回最もご紹介したかったのはこちらです。
たとえば、画像のURLが data に格納されているとして、それをv-forを使って
タグのsrcの値として設定したい場合。
または、何らかのURLの末尾に連結して使用したい場合。
そんな時は、v-bind を使用すると、希望する結果を得ることができます。

<template>
  <v-sheet>
    <v-slide-group multiple show-arrows>
      <v-slide-item v-for="n in 8" :key="n">
        <v-card style="margin: 0 20px 0 0; width: 320px; height: 240px;">
          <v-img class="white--text align-end" height="120px" v-bind:src="'https://picsum.photos/320/240?grayscale&random='+n">
          <v-card-title>sample title {{ n }}</v-card-title>
          <v-card-text class="text--primary">
           {{ n }}番目のカードテキスト
          </v-card-text>
        </v-card>
      <v-slide-item>
    </v-slide-group>
  </v-sheet>
</template>

↑上記は、この記事の最初にご紹介した例の応用です。
6行目の画像URL部分に注目してみてください。

6行目に
v-bind:src=”‘https://picsum.photos/320/240?grayscale&random=’+n”
とある様に、
末尾 n の部分に
v-forで繰り返している回数の値が都度代入されます。

この例で使用している、
Lorem.picsum
というWebサービス(※サムネイル用の綺麗なサンプル画像をお手軽に表示させることのできるWebサービス)では、
URL末尾にパラメーターを渡すことで
ランダムなサムネイル画像を取得できる仕様になっています。

その仕様に沿って、
上記のコードで、v-for を使いパラメーターを渡しているため、
リロードをするたびに、
8枚のカードそれぞれが別々のランダムなサムネイル画像を取得できる仕組みになっている、というわけです。
次のリンク先から、同じ仕組みで実際に動いている様子を確認いただけます。

Vuetifyのサンプル_Slider&Carousel

data内に画像のURLが直接入っている場合

もちろん、data内に直接画像のURLが入っている場合も、
v-bind を使うことで、
動的に画像URLの値を渡すことができます。

<script>
  new Vue({
    el: '#app',
    vuetify: new Vuetify(),
    data: {
      items: [
        {
          src: 'https://picsum.photos/1087/750?grayscale&random=1',
        },
        {
          src: 'https://picsum.photos/1087/750?grayscale&random=2',
        },
        {
          src: 'https://picsum.photos/1087/750?grayscale&random=3',
        },
        {
          src: 'https://picsum.photos/1087/750?grayscale&random=4',
        }
      ]
    }
  })
</script>

↑例えば、上記の様なdataがあった場合、
次の様にv-forの中で指定すれば、期待通りの結果を得ることが可能です。
5行目で指定している様に、v-img のsrcの値として、
v-bind を行なうというわけです。

<template>
  <v-carousel>
    <v-carousel-item
      v-for="(item,i) in items" :key="i">
      <v-img v-bind:src="item.src" v-bind:lazy-src="item.src" class="grey lighten-2"></v-img>
    </v-carousel-item>
  </v-carousel>
</template>

参考URLなど

今回ご紹介したv-for、v-bindについては、以下のVue.js公式サイトに詳細が書かれています。
マスタッシュ構文についても、v-bindのページに書かれていますので、参考になるかと思います。
[v-for について]:
リストレンダリング — Vue.js
[v-bind について]:
テンプレート構文 — Vue.js

この記事のまとめ

今回は、Vue.jsの基本的なディレクティブの中から、
v-for と v-bind について、
これまでご紹介してきた
Vuetifyのサンプル例をまじえつつ、記事を書きました。

今後、もっと良い具体例が思いついたら、より良い記事を書きたいと思っています。

※この記事は、内容の品質向上を目的に、随時更新を行う場合があります。