8
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vue.jsのリストレンダリングを勉強する

Last updated at Posted at 2019-07-11

リストレンダリング

v-forで配列に要素をマッピングする

配列に基づいて、アイテムのリストをレンダリングするために、v-forディレクテイブを使用します。
v-forディレクティブはitem in itemsの形式で特別な構文を要求し、itemsは配列で、itemは配列要素を順不動で復されているエイリアスです。

html部分
<ul id="example">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    items: [
      { message: 'item1' },
      { message: 'item2' }
    ]
  }
})
ブラウザ画面
・item1
・item2

上記の例ではitems配列の要素をブラウザ画面にレンダリングしています。

v-forブロック内では、親スコープのプロパティへの完全なアクセスを持っています。
またv-forは現在のアイテムに対する配列のインデックスを、2つ目の引数としてサポートしてます。

html部分
<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を使って反復処理する事ができます。

html部分
<ul id="example">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    object: {
      title: '公式リファレンスをトレスしながら勉強',
      author: 'Sthudent Camilo',
      publishedAt: '2019-07-09'
    }
  }
})
ブラウザ画面
・公式リファレンスをトレスしながら勉強
・Sthudent Camilo
・2019-05-21

オブジェクトでは2つ目の引数にプロパティ名(key)もサポートされています。

html部分
<ul id="example">
  <li v-for="(value, name) in object">
    {{ name }} : {{ value }}
  </li>
</ul>
ブラウザ画面
・title : 公式リファレンスをトレスしながら勉強
・author : Sthudent Camilo
・publishedAt : 2019-07-09

javascriptは上記の例と同じ

オブジェクトはindexもサポートされています。

html部分
<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は各要素にその場でパッチを適応して、その特定のインデックスに何を描画するべきかを確実に反映します。

html部分
<ul id="example">
  <li v-for="value in object" v-bind:key="value.id">
    {{ value }}
  </li>
</ul>

繰り返されるDOMの内容が単純な場合や、性能向上のために標準の動作に意図的に頼る場合を除いて、可能なときはいつでもv-forkey属性を与えることがベストプラクティスです。

詳しく書かれている記事
Vue.js: v-forで項目インデックスをkey属性にしていいのか

【注意】

オブジェクトや配列のような非プリミティブ値をv-forのキーとして使わないでください。代わりに、プリミティブ値である文字列や数値を使ってください。

配列の変化を検出

変更メソッド

dataプロパティで宣言した配列に変更を加える配列メソッドは以下の通りです。

html部分
<ul id="example">
  <li v-for="item in items" v-bind:key="item.id">
    {{ item.message }}
  </li>
</ul>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    items: [
      { message: 'item1' },
      { message: 'item2' }
    ]
  }
})

push()

配列の末尾に要素を追加します

開発者モードのConsole
app.items.push({ message: 'item3' })
// 戻り値 push後のオブジェクトのlength

pop()

配列から最後の要素を取り除
配列の長さを変化させます

開発者モードのConsole
app.items.pop()
// 戻り値 popで取り除いた要素

shift()

配列から最初の要素を取り除
配列の長さを変化させます

開発者モードのConsole
app.items.shift()
// 戻り値 shiftで取り除いた要素

unshift()

配列の最初に1つ以上の要素を追加する

開発者モードのConsole
app.items.unshift({ message: 'item3' },{ message: 'item4' })
// 戻り値 unshift後のオブジェクトのlength

sort()

配列の要素を in placeでソートします。

開発者モードのConsole
app.items.sort()

reverse()

配列の要素を in placeで反転させます
最初の要素は最後に最後の要素は最初になります

開発者モードのConsole
app.items.reverse()

###配列の置き換え
変更メソッドは元の配列を変更します
しかし、変更を行わないメソッドもあります

filter()

引数として与えられたテスト関数を書く配列び対して実行し、それに合格した全ての配列要素からなる新しい配列を生成します。

html部分
<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>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    items: [
      { message: 'test' },
      { message: 'test' }
      { message: 'tess' }
    ],

    passed: []
  }
})
ブラウザ画面
filter前
・test
・test
・tess
filter後
開発者モードのConsole
app.passed = app.items.filter(
  pass => pass.message == 'test'
)
ブラウザ画面
filter前
・test
・test
・tess
filter後
・test
・test

concat()

配列に他の配列や値を繋いでできた新しい配列を作る

html部分
<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>
javascript部分
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後

開発者モードのConsole
app.items3 = app.items.concat(app.items2)
ブラウザ画面
concat前
・item1
・item2
・item3
concat後
・item1
・item2
・item3
・item4
・item5
・item6

slice()

指定された配列の一部をシャローコピーして、新しい配列オブジェクトを返します。
指定するさいに始めの配列番号と終わりの配列番号を指定したら、終わりの配列番号の要素は含まれません。

html部分
<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>
javascript部分
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後

開発者モードのConsole
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つの変更を検出することができません。

  • インデックスで要素を直接設定するとき。
  • 配列の長さを変更するとき
html部分
<ul id="example">
  <li v-for="item in items">
    {{ item }}
  </li>
</ul>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    items: [
      'item1',
      'item2'
    ]
  }
})

下記の例はインデックスで要素を直接設定したアンチパターンです。

開発者モードのConsole
app.items[1] = "item3"

自分で実行してみたところ、配列の中にあるオブジェクトのkeyを指定して変更する場合は問題なく実行されました。

下記の例は配列の長さを変更するアンチパターンです。

開発者モードのConsole
app.items.length = "item3"

上記の例に対する解決は存在します。
上記と同じ動作になりますが、リアクティブなシステム内で状況の更新を検出することができます。

インスタンスメソッド $set

インデックスで要素を直接設定する時にはインスタンスメソッド $setを使う事で解決できます。

開発者モードのConsole
app.$set(app.items, 1, 'item3')
// app.$set(変更を加える配列, 配列番号, 変更したい値 )

vm.splice()

配列の長さを変更するときは変更メソッドのspliceを使います。

開発者モードのConsole
app.items.splice(app.items.length,0,'item3')
// app.items.splice(追加する配列番号,削除する要素の数,追加する要素)

オブジェクトの変更検出の注意

javaScriptの制限のため、Vue.jsはプロパティの追加や削除を検出することはできません

html部分
<div id="example">
  {{ message }}
  {{ message2 }}
</div>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    message: 'オブジェクト'
  }
})
開発者モードのConsole
app.message2 = 'オブジェクト2'

Vue.jsは既に作成されたインスタンスに新しいルートイベントのリアクティブプロパティを動的に追加することはできない。しかし、インスタンスメソッド $setを使いネストされたオブジェクトにリアクティブなプロパティを追加することは可能です。

html部分
<ul id="example">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
javascript部分
let app = new Vue({
  el: '#example',
  data: {
    object: {
      title: '公式リファレンスをトレスしながら勉強',
      author: 'Sthudent Camilo',
      publishedAt: '2019-07-09'
    }
  }
})
開発者モードのConsole
app.$set(app.object,'message' ,'こんにちわ')
// app.$set(変更を加えるオブジェクト, 追加するkey名, 追加する値)

Object.assign()

すべての列挙可能なプロパティの値を、1つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。

html部分
<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>
javascript部分
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
開発者モードのConsole
app.object3 = Object.assign(app.object, app.object2)
// app.object3 = Object.assign(コピー先オブジェクト, コピー元オブジェクト)
ブラウザ画面
object1

公式リファレンスをトレスしながら勉強
社畜 カミロ
2019-07-11
リストレンダリング難しい…

object3

公式リファレンスをトレスしながら勉強
社畜 カミロ
2019-07-11
リストレンダリング難しい…

コピー先オブジェクトのプロパティは、コピー元に同じ名前のプロパティがあると上書きされます。
コピー先オブジェクトにコピー元オブジェクトが上書きされます。

コピー先オブジェクトにコピー元オブジェクトが上書き対策として下記方法があります。
両方のオブジェクトのプロパティを使用して新しいオブジェクト作成する方法です。

開発者モードのConsole
app.object3 = Object.assign({}, app.object, app.object2)
ブラウザ画面
object1

公式リファレンスをトレスしながら勉強
Sthudent Camilo
2019-07-09

object3

公式リファレンスをトレスしながら勉強
社畜 カミロ
2019-07-11
リストレンダリング難しい…

フィルタ/ソートされた結果の表示

元のデータを実際に変更またはリセットすることなしに、フィルタリングやソートされたバージョンの配列を表示したいことがあります。
フィルタリングやソートされた配列を返す算出プロパティを作ることができます。

html部分
<div id="example">
  <ul>
    <p>配列 フィルタ/ソートされた結果の表示</p>
    <li v-for="value in evenNumbers">
      {{ value }}
    </li>
  </ul>
</div>
javascript部分
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
      })
    }
  }
})

算出プロパティが使えない状況ではメソッドを使う事ができる。

html部分
<div id="example">
  <ul>
    <p>配列 フィルタ/ソートされた結果の表示</p>
    <li v-for="value in even(numbers)">
      {{ value }}
    </li>
  </ul>
</div>
javascript部分
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は整数値を取ることもできる。

htm部分
<div id="example">
  <ul>
    <li v-for="value in 10">
      item{{ value }}
    </li>
  </ul>
</div>

上記の例では、指定された数だけ< li >要素が繰り返されます。

コンテンツテンプレートでのv-for

v-if同様に、複数の要素ブロックをレンダリングするために、v-forで < template >タグを使うこともできます。

html部分
<ul id="example">
  <template v-for="value in object">
    <li>{{ value }}</li>
  </template>
</ul>
javascript部分
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で配列やオブジェクトをループする良い方法を真剣に検討してみた

8
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?