リストレンダリング
v-forで配列に要素をマッピングする
配列に基づいて、アイテムのリストをレンダリングするために、v-forディレクテイブを使用します。
v-forディレクティブはitem in itemsの形式で特別な構文を要求し、itemsは配列で、itemは配列要素を順不動で復されているエイリアスです。
<ul id="example">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
items: [
{ message: 'item1' },
{ message: 'item2' }
]
}
})
・item1
・item2
上記の例ではitems配列の要素をブラウザ画面にレンダリングしています。
v-forブロック内では、親スコープのプロパティへの完全なアクセスを持っています。
またv-forは現在のアイテムに対する配列のインデックスを、2つ目の引数としてサポートしてます。
<ul id="example">
<li v-for="(item, index) in items">
[配列番号:{{ index }}] - [配列要素:{{ item.message }}]
</li>
</ul>
・[配列番号:0] - [配列要素:item1]
・[配列番号:1] - [配列要素:item2]
javascript部分は上記の例と同じです。
indexは配列の要素番号です。
また、区切り文字としてinの他にofを使用することができます。
これはjavascriptのイテレータ構文に近いものです。
オブジェクトのv-for
オブジェクトのプロパティに対して、v-forを使って反復処理する事ができます。
<ul id="example">
<li v-for="value in object">
{{ value }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
object: {
title: '公式リファレンスをトレスしながら勉強',
author: 'Sthudent Camilo',
publishedAt: '2019-07-09'
}
}
})
・公式リファレンスをトレスしながら勉強
・Sthudent Camilo
・2019-05-21
オブジェクトでは2つ目の引数にプロパティ名(key)もサポートされています。
<ul id="example">
<li v-for="(value, name) in object">
{{ name }} : {{ value }}
</li>
</ul>
・title : 公式リファレンスをトレスしながら勉強
・author : Sthudent Camilo
・publishedAt : 2019-07-09
javascriptは上記の例と同じ
オブジェクトはindexもサポートされています。
<ul id="example">
<li v-for="(value, name, index) in object">
{{ index }} . {{ name }} : {{ value }}
</li>
</ul>
0 . title : 公式リファレンスをトレスしながら勉強
1 . author : Sthudent Camilo
2 . publishedAt : 2019-07-09
【注意】
オブジェクトを反復処理するとき、順序はObject.keys() の列挙順のキーに基いており、全てのjavascriptエンジンの実装で一貫性で保証されていません。
状態の維持
※正直この題目はピンときていので理解が深まり次第追記します。
Vue.jsがv-forで描画された要素のリストを更新する際、標準では”その場でパッチを適応する”方法が用いられます。
データのアイテムの順序が変更された場合、アイテムの順序に合わせてDOM要素を移動する代わりに、Vueは各要素にその場でパッチを適応して、その特定のインデックスに何を描画するべきかを確実に反映します。
<ul id="example">
<li v-for="value in object" v-bind:key="value.id">
{{ value }}
</li>
</ul>
繰り返されるDOMの内容が単純な場合や、性能向上のために標準の動作に意図的に頼る場合を除いて、可能なときはいつでもv-forにkey属性を与えることがベストプラクティスです。
詳しく書かれている記事
Vue.js: v-forで項目インデックスをkey属性にしていいのか
【注意】
オブジェクトや配列のような非プリミティブ値をv-forのキーとして使わないでください。代わりに、プリミティブ値である文字列や数値を使ってください。
配列の変化を検出
変更メソッド
dataプロパティで宣言した配列に変更を加える配列メソッドは以下の通りです。
<ul id="example">
<li v-for="item in items" v-bind:key="item.id">
{{ item.message }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
items: [
{ message: 'item1' },
{ message: 'item2' }
]
}
})
push()
配列の末尾に要素を追加します
app.items.push({ message: 'item3' })
// 戻り値 push後のオブジェクトのlength
pop()
配列から最後の要素を取り除
配列の長さを変化させます
app.items.pop()
// 戻り値 popで取り除いた要素
shift()
配列から最初の要素を取り除
配列の長さを変化させます
app.items.shift()
// 戻り値 shiftで取り除いた要素
unshift()
配列の最初に1つ以上の要素を追加する
app.items.unshift({ message: 'item3' },{ message: 'item4' })
// 戻り値 unshift後のオブジェクトのlength
sort()
配列の要素を in placeでソートします。
app.items.sort()
reverse()
配列の要素を in placeで反転させます
最初の要素は最後に最後の要素は最初になります
app.items.reverse()
###配列の置き換え
変更メソッドは元の配列を変更します
しかし、変更を行わないメソッドもあります
filter()
引数として与えられたテスト関数を書く配列び対して実行し、それに合格した全ての配列要素からなる新しい配列を生成します。
<ul id="example">
<p>filter前</p>
<li v-for="item in items" v-bind:key="item.id">
{{ item.message }}
</li>
<p>filter後</p>
<li v-for="item in passed" v-bind:key="item.id">
{{ item.message }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
items: [
{ message: 'test' },
{ message: 'test' }
{ message: 'tess' }
],
passed: []
}
})
filter前
・test
・test
・tess
filter後
app.passed = app.items.filter(
pass => pass.message == 'test'
)
filter前
・test
・test
・tess
filter後
・test
・test
concat()
配列に他の配列や値を繋いでできた新しい配列を作る
<ul id="example">
<p>concat前</p>
<li v-for="item in items" v-bind:key="item.id">
{{ item.message }}
</li>
<p>concat後</p>
<li v-for="item in items3" v-bind:key="item.id">
{{ item.message }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
items: [
{ message: 'item1' },
{ message: 'item2' },
{ message: 'item3' }
],
items2: [
{ message: 'item4' },
{ message: 'item5' },
{ message: 'item6' }
],
items3: []
}
})
concat前
・item1
・item2
・item3
concat後
app.items3 = app.items.concat(app.items2)
concat前
・item1
・item2
・item3
concat後
・item1
・item2
・item3
・item4
・item5
・item6
slice()
指定された配列の一部をシャローコピーして、新しい配列オブジェクトを返します。
指定するさいに始めの配列番号と終わりの配列番号を指定したら、終わりの配列番号の要素は含まれません。
<ul id="example">
<p>slice前</p>
<li v-for="(item, index) in items" v-bind:key="item.id">
{{ index }} : {{ item.message }}
</li>
<p>slice後</p>
<li v-for="(item, index) in items2" v-bind:key="item.id">
{{ index }} : {{ item.message }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
items: [5
{ message: 'item1' },
{ message: 'item2' },
{ message: 'item3' },
{ message: 'item4' }
],
items2: []
}
})
slice前
・0 : item1
・1 : item2
・2 : item3
・3 : item4
slice後
app.items2 = app.items.slice(1,3)
slice前
・0 : item1
・1 : item2
・2 : item3
・3 : item4
slice後
・0 : item2
・1 : item3
注意事項
javaScriptの制限のため、Vue.jsは配列下記2つの変更を検出することができません。
- インデックスで要素を直接設定するとき。
- 配列の長さを変更するとき
<ul id="example">
<li v-for="item in items">
{{ item }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
items: [
'item1',
'item2'
]
}
})
下記の例はインデックスで要素を直接設定したアンチパターンです。
app.items[1] = "item3"
自分で実行してみたところ、配列の中にあるオブジェクトのkeyを指定して変更する場合は問題なく実行されました。
下記の例は配列の長さを変更するアンチパターンです。
app.items.length = "item3"
上記の例に対する解決は存在します。
上記と同じ動作になりますが、リアクティブなシステム内で状況の更新を検出することができます。
インスタンスメソッド $set
インデックスで要素を直接設定する時にはインスタンスメソッド $setを使う事で解決できます。
app.$set(app.items, 1, 'item3')
// app.$set(変更を加える配列, 配列番号, 変更したい値 )
vm.splice()
配列の長さを変更するときは変更メソッドのspliceを使います。
app.items.splice(app.items.length,0,'item3')
// app.items.splice(追加する配列番号,削除する要素の数,追加する要素)
オブジェクトの変更検出の注意
javaScriptの制限のため、Vue.jsはプロパティの追加や削除を検出することはできません
<div id="example">
{{ message }}
{{ message2 }}
</div>
let app = new Vue({
el: '#example',
data: {
message: 'オブジェクト'
}
})
app.message2 = 'オブジェクト2'
Vue.jsは既に作成されたインスタンスに新しいルートイベントのリアクティブプロパティを動的に追加することはできない。しかし、インスタンスメソッド $setを使いネストされたオブジェクトにリアクティブなプロパティを追加することは可能です。
<ul id="example">
<li v-for="value in object">
{{ value }}
</li>
</ul>
let app = new Vue({
el: '#example',
data: {
object: {
title: '公式リファレンスをトレスしながら勉強',
author: 'Sthudent Camilo',
publishedAt: '2019-07-09'
}
}
})
app.$set(app.object,'message' ,'こんにちわ')
// app.$set(変更を加えるオブジェクト, 追加するkey名, 追加する値)
Object.assign()
すべての列挙可能なプロパティの値を、1つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。
<div id="example">
<ul>
<p>object1</p>
<li v-for="value in object">
{{ value }}
</li>
<p>object3</p>
<li v-for="value in object3">
{{ value }}
</li>
</ul>
</div>
let app = new Vue({
el: '#example',
data: {
object: {
title: '公式リファレンスをトレスしながら勉強',
author: 'Sthudent Camilo',
publishedAt: '2019-07-09'
},
object2: {
subtitle: 'リストレンダリング難しい…',
author: '社畜 カミロ',
publishedAt: '2019-07-11'
},
object3:{}
}
})
object1
公式リファレンスをトレスしながら勉強
Sthudent Camilo
2019-07-09
object3
app.object3 = Object.assign(app.object, app.object2)
// app.object3 = Object.assign(コピー先オブジェクト, コピー元オブジェクト)
object1
公式リファレンスをトレスしながら勉強
社畜 カミロ
2019-07-11
リストレンダリング難しい…
object3
公式リファレンスをトレスしながら勉強
社畜 カミロ
2019-07-11
リストレンダリング難しい…
コピー先オブジェクトのプロパティは、コピー元に同じ名前のプロパティがあると上書きされます。
コピー先オブジェクトにコピー元オブジェクトが上書きされます。
コピー先オブジェクトにコピー元オブジェクトが上書き対策として下記方法があります。
両方のオブジェクトのプロパティを使用して新しいオブジェクト作成する方法です。
app.object3 = Object.assign({}, app.object, app.object2)
object1
公式リファレンスをトレスしながら勉強
Sthudent Camilo
2019-07-09
object3
公式リファレンスをトレスしながら勉強
社畜 カミロ
2019-07-11
リストレンダリング難しい…
フィルタ/ソートされた結果の表示
元のデータを実際に変更またはリセットすることなしに、フィルタリングやソートされたバージョンの配列を表示したいことがあります。
フィルタリングやソートされた配列を返す算出プロパティを作ることができます。
<div id="example">
<ul>
<p>配列 フィルタ/ソートされた結果の表示</p>
<li v-for="value in evenNumbers">
{{ value }}
</li>
</ul>
</div>
let app = new Vue({
el: '#example',
data: {
numbers:[1,2,3,4,5]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
算出プロパティが使えない状況ではメソッドを使う事ができる。
<div id="example">
<ul>
<p>配列 フィルタ/ソートされた結果の表示</p>
<li v-for="value in even(numbers)">
{{ value }}
</li>
</ul>
</div>
let app = new Vue({
el: '#example',
data: {
numbers:[1,2,3,4,5]
},
methods:{
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
範囲付き v-for
v-forは整数値を取ることもできる。
<div id="example">
<ul>
<li v-for="value in 10">
item{{ value }}
</li>
</ul>
</div>
上記の例では、指定された数だけ< li >要素が繰り返されます。
コンテンツテンプレートでのv-for
v-if同様に、複数の要素ブロックをレンダリングするために、v-forで < template >タグを使うこともできます。
<ul id="example">
<template v-for="value in object">
<li>{{ value }}</li>
</template>
</ul>
let app = new Vue({
el: '#example',
data: {
object: {
title: '公式リファレンスをトレスしながら勉強',
author: 'Sthudent Camilo',
publishedAt: '2019-07-09'
}
}
})
あとがき
v-ifとv-forの題目はv-ifとv-forを同時に利用する事は推奨されておらずバッドプラクティスですということです。
参考資料
javascriptのループについての記事ですが、javascriptのイテレータ構文に近いのでVue.jsのv-forバインディングにも役に立ちます
JavaScriptで配列やオブジェクトをループする良い方法を真剣に検討してみた