第7回 Vue.js入門 v-forディレクティブ

roop プログラミング

こんにちは、コンスキです。

今回はv-forディレクティブというディレクティブの説明をします。

ここまでですでに3つのディレクティブを紹介してきていて、今回で4つ目のディレクティブとなります。これから説明するv-forディレクティブはその4つの中でも、私が個人的に使えるようになるのに一番時間がかかったディレクティブです。

その原因はfor文に対する思い込みでした。

v-forと名前にforがついているため、「for(初期化式; 条件式; 反復式; )」のような形のfor文を思い浮かべる方もいるのではないでしょうか。実は私も最初はこのようなものだと思っていました。

しかし、どちらかというと「変数名 in オブジェクトや配列」の形のfor文に考え方が似ているため、あらかじめ承知しておくと理解が早まると思います。

v-forディレクティブの使い方

基本的な使い方

v-forディレクティブの基本的な書き方は次のようになります。

HTML側↓

<div id="app">
    <要素名 v-for="変数名 in オブジェクトまたは配列のキー">{{ 変数名 }}</要素名>
</div>

Javascript側↓

const vm = new Vue({
    el: "#app",
    data: {
        オブジェクトまたは配列のキー: オブジェクトまたは配列
    }
})

以上が基本的な書き方となりますが、書き方を見ただけでは使い方が全然わかりませんよね。書いてあることが何を意味しているのかを説明します。

まずはHTML側の記述についてです。v-forもこれまでのディレクティブのように要素名の属性として書くことになります。独特なのは属性値(”変数名 in オブジェクトまたは配列”)の部分です。

これまでとは違って、dataプロパティに設定した値のキーをそのまま書きません。オブジェクトまたは配列と書かれていますが、これは値を取り出してくるオブジェクトや配列のことを指しています。

ここから値を取り出してきて、「変数名」をつけた変数に1つづつ代入代入していき、その変数を使った要素を画面に表示していきます。

つまり、オブジェクトのプロパティの数や配列の長さの分だけv-forを書いた要素が繰り返されます。

例として次のコードをブラウザ上に表示してみます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>v-forディレクティブ</title>
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="animal in animals">{{ animal }}</li>
        </ul>   
    </div>
    <script>
        const vm = new Vue({
            el: "#app",  
            data: {
                animal : ["ライオン","ウサギ","サル","ネコ"]
            }    
        })
    </script>    
</body>
</html>

ブラウザ上の表示↓

上のようにanimalsというdataプロパティに設定した配列の要素が順番に表示されましたでしょうか?

上のコードではliタグにv-forディレクティブを使っているため動物の名前の前に点がついていますが、他の要素であればこの点は付きません。

次のように書くことで、繰り返す要素の中にオブジェクトのプロパティのキーや配列のインデックスを使うこともできます。

繰り返す要素にオブジェクトのキーを使う↓

<div id="app">
    <要素名 v-for="(変数名, キーの名前) in オブジェクトまたは配列のキー">{{ キーの名前 }}:{{ 変数名 }}</要素名>
</div>

繰り返す要素に配列のインデックスを使う↓

<div id="app">
    <要素名 v-for="(変数名, インデックス名) in オブジェクトまたは配列のキー">{{ インデックス名 }}:{{ 変数名 }}</要素名>
</div>

変数名、キーの名前、インデックス名は自分で決めることができますがわかりやすい名前にしましょう。

変数名を決める際、例えばプロパティのに設定しているオブジェクトのプロパティのキーが「items」だった場合は変数名は「item」にしたり、配列のキーが「people」だった場合は変数名は「person」にしたりすると、変数とオブジェクトや配列との関係がわかりやすくなると思います。

またキーの名前とインデックス名は、特別な理由がない限りそれぞれ「key」と「index」にすると、ほかのプロパティ名や変数名と名前がかぶってしまうことを防げると思います。

それでは、オブジェクトのプロパティのキーを使った例として、次のコードをブラウザ上に表示してみてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>v-forディレクティブ</title>
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="(feature, key) in features">{{ key }}:{{ feature }}</li>
        </ul>   
    </div>
    <script>
        const vm = new Vue({
            el: "#app",  
            data: {
                features: {
                    name: "太郎",
                    age: 19,
                    sex: "男",
                    height: 165
                } 
            }    
        })
    </script>    
</body>
</html>

ブラウザ上の表示↓

featuresというオブジェクトのプロパティのキーが値と一緒に使われましたね。

応用的な使い方

v-forディレクティブの基本的な使い方がわかったら、応用的な使い方についてみていきます。

v-forディレクティブを使った際に、プロパティのに設定してある複雑なオブジェクトや配列の値を使いたいときがあると思います。

複雑なオブジェクトや配列とは次のような複数の層になっているものです。

data: {
    students: [
        {
            name: "太郎",
            age: 19
        },
        {
            name: "次郎",
                age: 16
        },
        {
            name: "花子",
            age: 17
        }
    ]
}

例えば、dataプロパティに上のようなオブジェクトの配列があった場合を考えてください。配列は生徒の情報を入れたオブジェクトの配列です。そのオブジェクトの中から生徒の名前を順番に画面に表示させるときは次のようなコードになります。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>v-forディレクティブ</title>
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="student in students">{{ student.name }}</li>
        </ul>   
    </div>
    <script>
        const vm = new Vue({
            el: "#app",  
            data: {
                students: [
                    {
                        name: "太郎",
                        age: 19
                    },
                    {
                        name: "次郎",
                            age: 16
                    },
                    {
                        name: "花子",
                        age: 17
                    }
                ]
            }    
        })
    </script>    
</body>
</html>

ブラウザ上の表示↓

上のようにブラウザには、繰り返したオブジェクトではなく、オブジェクトの中身であるnameの値が表示されます。{{ student.name }}のようにドット演算子を使っているのがわかるでしょうか。

言葉にするとすごくわかりにくいのですが、上の例コードのようにオブジェクトの配列を繰り返す場合で、オブジェクトを表示するのではなく値を表示したいときにドット演算子を使います。

逆に言うとv-forディレクティブとドット演算子を一緒に使うときは次のような時です。

書き方のテンプレートとしては、下のようになります。
HTML側↓

<div id="app">
    <要素名 v-for="変数名 in dataプロパティに設定したオブジェクトの配列のキー">{{ 変数名.表示したい値のキー }}</要素名>
</div>

Javascript側↓

const vm = new Vue({
    el: "#app",  
    data: {
        キー: [


          {
                 キー:値 ,
                 キー:値 
             },
             {

                 キー:値,
                 キー:値    
             },
              ︙
        ]
    }    
})

同じ色のところにはが同じものを書きます。

「オブジェクトの配列のキー」と「表示したい値のキー」は何を指しているのかわからないかもしれませんが、先ほどの例でいう名前だけを表示したので次のものを指しています。

説明が下手で意味がわからなかったら本当にすみません(;_;)

v-forディレクティブを使うときの決まり事?

Vue.jsの公式サイトには、

繰り返される DOM の内容が単純な場合や、性能向上のために標準の動作に意図的に頼る場合を除いて、可能なときはいつでも v-for に key 属性を与えることが推奨されます。

Vue.js 公式ガイド

という記述があります。

これはv-forを使った要素に対して「v-bind:key=”文字列や数値”」を書き加えることが推奨されているということのようです。

例えば、すでに少し上に書いたオブジェクトの配列を使った例でいうと次のようになります。

<div id="app">
    <ul>
        <li v-for="student in students" v-bind:key="student.name">{{ student.name }}</li>
    </ul>   
</div>

これは要素のはキーとしてnameという文字列を使った例ですが、「v-bind:key=”student.age”」のように数値でもいいみたいです。ただし、配列やオブジェクトなどは使えないそうです。

Vue.jsに関する知識が足りておらず、なぜこのように書く必要があるのかをまだ完全に私は理解していません。それにもかかわらず紹介して申し訳ございませんが、要素にアニメーションを付け加えた際などに後々何かしらの不都合が生じるようです。

そこで、理解できないうちは決まり事として書くようにしようと私は思っています。

v-forディレクティブをサンプルプログラムで使う

ここからはサンプルプログラムをつくっていきます。今回はこれまでに説明した内容を詰め込んだプログラムをつくります。

それではつくるプログラムの内容を説明します。

まず3人の人を想定して、それぞれの身長と体重からBMIを求めます。それから名前、身長と体重、BMIを3人分表示します。そして、BMIが25以上の人には「肥満気味です」の文字を表示し、さらにそのBMIを強調します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>v-forディレクティブ</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
    <div id="app">
        <!-- 他の配列の要素の指定を行うためにindex配列peopleのインデックスを使う -->
        <div v-for="(person, index) in people" v-bind:key="person.name">    
            <p>名前:{{ person.name }}</p>
            <p>身長:{{ person.height }}cm</p>
            <p>体重:{{ person.weight }}kg</p>
            <p v-bind:style="styleOject[index]">BMI:{{calcBMI[index]}}</p>
            <p v-show="isBitBig[index]">肥満気味です</p>
            <br>
        </div>
    </div>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                people : [
                    {
                        name: "太郎",
                        height: 170,
                        weight: 70
                    },
                    {
                        name: "花子",
                        height: 160,
                        weight: 55
                    },
                    {                
                        name: "次郎",
                        height: 162,
                        weight: 60
                    }
                ],
                //BMIが25以上の時に適用させるstyleオブジェクト
                alertObject: {
                    color: '#FF7070',
                    fontWeight: 'bold',
                    border: '4px double #FF7070', 
                    display: 'inline'
                }
            },
            computed: {
                calcBMI: function () {
                    var BMI = [] ;
                    for(var i = 0; i < this.people.length; i++) {
                        var mHeight = this.people[i].height / 100;
                        BMI.push(Math.floor(this.people[i].weight / mHeight / mHeight));
                    }
                    return BMI
                },    
                isBitBig: function () {
                    var flag = [];    //
                    for(var i = 0; i < this.people.length; i++) {
                        if(this.calcBMI[i] >= 25) {
                            flag.push(true);
                        } else {
                            flag.push(false);
                        }               
                    }    
                    return flag
                },
                styleOject: function () {
                    var styleOjects = [];    //全員のsyleオブジェクトを入れておくリスト
                    for(var i = 0; i < this.people.length; i++) {
                    //BMIが25以上だったらdataプロパティにあるstyleオブジェクト返し、25未満だったら空のオブジェクトを返す
                    var so = this.isBitBig[i] ? this.alertObject : {};  
                        styleOjects.push(so);
                    }
                    return styleOjects
                }
            }
        })
    </script>
</body>
</html>

このプログラム実行するとブラウザ上には次のように表示されます。

3人のうち誰一人BMIが25以上である人がいないため、「肥満気味です」というメッセージは表示されていません。同じように、BMIを強調するstyleも有効になっていないようです。

それでは、Google DevToolsを使用して、太郎の体重を変化させてみましょう。Google DevToolsを開けたら、Consoleタブを選択して文字が打てる部分に次のコードを入力し、Enterキーを押してください。

m.$data.people[0].weight = 75 

すると、次のように太郎のBMIの下に「肥満気味です」のメッセージが表示され、同時にBMIが強調されると思います。

他の人の体重や身長もコンソールをつかって変化させてみると、計算されたBMIが25を超えるようであれば同じようにメッセージの表示とBMIの強調が行われると思います。ぜひ試してみてください。

一方で、すでにメッセージの表示とBMIの強調がされている人の体重などを変化させて、BMIが25を下回るとメッセージは消えて、BMIの強調もなくなります。

以上で今回の説明を終わりにします。最後まで読んでくれてありがとうございました。次回は、要素のクリックやフォームへの入力が行われたときに、データを変更することができるv-onディレクティブの説明をします。

v-onディレクティブとv-bindディレクティブを組わせると疑似的に双方向バインディングを行えます。二方向バインディングを使えれば、これまでの一方向バインディングではできなかったことができるようになり、凝ったプログラムをつくることができるようになります。

まとめ

今回分かったこと

  • ・v-forディレクティブを使うと要素を繰り返し表示することができる
  • ・繰り返し表示にはオブジェクトと配列から取り出した値を使うことができる
  • ・繰り返し表示で重なっているオブジェクトとや配列から取り出すときはドット演算子を使う
  • ・v-forディレクティブを使うときは「v-bind:key:”文字列や数値”」も一緒に記述するとよい

コメント

タイトルとURLをコピーしました