リストレンダリング
v-for
私達は配列に基づいて、アイテムのリストをレンダリングするために、v-for
ディレクティブを使用することができます。v-for
ディレクティブは item in items
の形式で特別な構文を要求し、items
はソースデータの配列で、item
は配列要素がその上で反復されているエイリアスです:
例:
<ul id="example-1"> |
var example1 = new Vue({ |
結果:
- {{item.message}}
v-for
ブロック内では、私達が親スコープのプロパティへ完全なアクセスに加えて、恐らく推測しているとおり、現在のアイテムに対する配列のインデックスで特別な変数 $index
を持っています:
<ul id="example-2"> |
var example2 = new Vue({ |
結果:
- {{ parentMessage }} - {{ $index }} - {{ item.message }}
あるいは、インデックス(または、オブジェクト使用されている場合はキー)に対してエイリアスを指定することもできます:
<div v-for="(index, item) in items"> |
テンプレートでの v-for
テンプレート v-if
と同様、複数の要素のブロックをレンダリングするために v-for
で <template>
タグも使用することができます。例えば:
<ul> |
配列の変化を検出
変更メソッド
Vue.js は View の更新もトリガするために、監視された配列の変更メソッドをラップ (wrap) します。ラップされたメソッドは次のとおりです:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
コンソールを開いて前の items
配列の例で変更メソッドを呼び出して遊んでみてください。例えば example1.items.push({ message: 'Baz' })
のようにしてみましょう。
配列の置き換え
変更メソッドは、名前が示唆するように、それらが呼ばれると元の配列を変更します。変更しないメソッドもあります。例えば、filter()
、concat()
、そしてslice()
のような、元の配列を変更しませんが、常に新しい配列を返します。変更しないメソッドで動作するとき、新しいもので古い配列を置き換えます:
example1.items = example1.items.filter(function (item) { |
これは、Vue.js が既存の DOM を捨てて、リスト全体を再レンダリングの原因になると思うかもしれません。幸いにもそれはそうではありません。Vue.js は DOM 要素の再利用を最大化するためにいくつかのスマートなヒューリスティックを実装しているので、重複するオブジェクトを含んでいる他の配列を配列で置き換えることは、とても効率的な作業です。
track-by
いくつかのケースで、完全に新しいオブジェクトで配列を置き換える必要があるかもしれません(例えば、API コールから作成されたオブジェクトなど)。デフォルトでは、v-for
は既存のスコープとそのデータオブジェクトの識別情報を追跡することによって、DOM 要素の再利用性を決定するので、リスト全体が再レンダリングされる可能性があります。しかしながら、もし、各データオブジェクトがユニークな ID プロパティを持っているならば、できるだけ多くのインスタンスを再利用するための Vue.js へのヒントとして、track-by
特別な属性を利用することができます。
例として、もし data が下記のようならば:
{ |
このようにヒントを与えることができます:
<div v-for="item in items" track-by="_uid"> |
後で、items
配列を置き換え、そして Vue.js は _uid: '88f869d'
を持つ新しいオブジェクトを検出するとき、同じ _uid
と関連する既存スコープと DOM 要素を再利用することができます。
track-by $index
追跡するためにユニークなキーを持っていない場合、track-by="$index"
も利用できます。これは、v-for
を in-place 更新モードに強制します。フラグメントはもはや並べ替えておらず、それらは単純に対応するインデックスに新しい値でフラッシュして取得します。このモードはソースとなる配列に重複する値を扱うことができます。
これは配列の置き換えは非常に効率的にできますが、トレードオフもあります。なぜなら、DOM ノードはもはや順序の変更を反映するように移動されていないため、DOM 入力値とコンポーネントのプライベートな状態のような一時的な状態は同期できないです。このため、v-for
ブロックが input 要素または子コンポーネントから含まれている場合は、track-by="$index"
を使用するとき注意してください。
注意事項
JavaScript の制限のため、Vue.js は配列で以下の変更を検出することはできません:
- インデックスでアイテムを直接設定するとき。例:
vm.items[0] = {}
- 配列の長さを変更するとき。例:
vm.items.length = 0
上記の注意事項 (1) に対処するため、Vue.js は監視された配列を $set()
メソッドで拡張します:
// `example1.items[0] ...` と同じであるが、View の更新をトリガする |
上記の注意事項 (2) に対処するため、代わりに空の配列で items
を置き換えてください。
$set()
に加えて、Vue.js は配列を便利なメソッド $remove()
で拡張し、そのメソッドは、検索し、そして内部では splice()
を呼びだすことによって対象の配列からアイテムを削除します。そういうわけで代わりは:
var index = this.items.indexOf(item) |
というようになり、これと同じことをこのように行うことができます:
this.items.$remove(item) |
Object.freeze()
の使用
Object.freeze()
によって凍結されたオブジェクトの配列を反復するとき、明示的に track-by
キーを使用する必要があります。Vue.js は自動的にオブジェクトを追跡することが出来ないときは、このシナリオにおいて、警告が表示されます。
オブジェクトの v-for
オブジェクトのプロパティに対して、v-for
を使って反復処理することができます。$index
に加えて、それぞれのスコープは $key
という特別なプロパティにアクセスします。
<ul id="repeat-object" class="demo"> |
new Vue({ |
結果:
- {{ $key }} : {{ value }}
キーに対してエイリアスも提供できます:
<div v-for="(key, val) in object"> |
オブジェクトを反復処理するとき、順序は Object.keys()
の列挙順のキーに基づいており、全ての JavaScript エンジンの実装で一貫性が保証されていません。
範囲の v-for
v-for
は整数値を取ることも出来ます。このケースでは、指定された数だけテンプレートが繰り返されます。
<div> |
結果:
フィルタ/ソートされた結果の表示
時どき、私達は実際に変更するかまたは元のデータをリセットせずに配列フィルタリングやソートされたバージョンの配列を表示する必要があります。これを達成するに2つのオプションがあります:
- フィルタまたはソートされた配列を返す算出プロパティを作成する
- 組み込み
filterBy
そしてorderBy
されたフィルタを使用する
それは完全な JavaScript なため、算出プロパティはあなたにより細かい制御と柔軟性を与えますが、フィルタは共通ユースケースに対してより便利にすることができます。配列フィルタの詳細な使用方法については、それらのドキュメントをチェックしてください。