title | type | order |
---|---|---|
Me-render Daftar |
guide |
8 |
Kita dapat menggunakan direksi v-for
untuk me-render sebuah daftar item berdasakan dari sebuah array. Direksi v-for
membutuhkan sebuah sintaks spesial dalam bentuk item in items
, dimana items
adalah sumber data array dan item
adalah alias untuk elemen array yang diperulangkan:
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
Result:
{% raw %}
- {{item.message}}
Didalam blok v-for
kita memiliki akses penuh kepada cangkupan properti parent. v-for
juga mendukung sebuah argumen opsional kedua untuk index dari item saat ini.
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
Result:
{% raw%}
- {{ parentMessage }} - {{ index }} - {{ item.message }}
Kalian juga bisa menggunakan of
sebagai pembatass sebagai pengganti in
, supaya lebih mirip dengan sintaks dari JavaScript untuk perulangan:
<div v-for="item of items"></div>
Kalian juga bisa menggunakan v-for
untuk melakukan perulangan melalui properti dari sebuah objek.
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
Result:
{% raw %}
- {{ value }}
Kalian juga dapat menyediakan sebuah argumen ke dua sebagai kunci:
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
{% raw %}
Dan argumen lain sebagai index:
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
{% raw %}
Ketika melakukan perulangan pada sebuah objek, urutannya berdasarkan pada urutan penomoran kunci dari `Object.keys()`, yang mana **tidak** digaransi untuk dapat konsisten pada sebagian besar implementasi mesin JavaScript.
Ketika Vue memperbarui sebuah daftar elemen yang di-render dengan v-for
, secara standar menggunakan sebuah strategi "patch di-tempat". Jika urutan datanya berubah, dibanding memindahkan elemen DOM untuk mencocokkan urutan dari item tersebut, Vue akan melakukan patch ke setiap element di-tempat dan memastikan untuk menampilkan apa yang seharusnya di-render pada index tertentu tersebut. Hal ini mirip dengan kelakuan dari track-by="$index"
pada Vue 1.x.
Mode standar ini efisian, tetapi hanya cocok ketika render output daftar kalian tidak bergantung pada komponen state child atau state DOM sementara (contohnya nilai input formulir).
Untuk memberikan Vue sebuah petunjuk agar dapat melacak setiap identitas node, yang kemudian menggunakan ulang dan mengurutkan kembali element yang sudah ada, kalian harus menyediakan sebuah attribut key
yang unik untuk setiap item. Sebuah nilai ideal untuk key
akan menjadi id unik untuk setiap item. Attribut spesial ini kurang lebih sama dengan track-by
pada 1.x, tetapi bekerja seperti attribut, jadi kalian harus menggunakan v-bind
untuk mengikatnya agar nilainya dinamis (disini menggunakan shorthand):
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
Direkomendasikan untuk menyediakan sebuah key
bersama dengan v-for
kapanpun, kecuali konten DOM yang diperulangkan sederhana, atau kalian sengaja mengandalkan perbuatan standar untuk meningkatkan performa.
Karena mengidentifikasi node adalah mekanisme umum untuk Vue, key
tersebut juga memiliki kegunaan lain yang tidak dibuat khusus untuk v-for
, yang akan kita lihat di panduan nanti.
Jangan menggunakan nilai _non-primitive_ seperti objek dan array untuk kunci `v-for`. Gunakan _string_ atau nilai angka saja.
Vue membukus metode mutasi dari array yang diamati agar mereka akan dapat memicu pembaruan tampilan. Metode yang dibungkus adalah:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Kalian bisa membuka console dan bermain dengan contoh array items
sebelumnya dengan memanggil metode mutasi mereka. Contohnya: example1.items.push({ message: 'Baz' })
.
Metode mutasi, seperti namanya, memutasi array asli dimana mereka dipanggil. Sebagai perbandingan, ada juga metode non-mutasi, contohnya filter()
, concat()
dan slice()
, dimana tidak memutasi array asli tetapi selalu mengembalikan sebuah array baru. Ketika bekerja dengan metode non-mutasi, kalian dapat mengganti array lama dengan array yang baru:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
Kalian mungkin pikir hal ini akan menyebabkan Vue untuk membuang DOM yang sudah ada dan melakukan render lagi ke semua daftar - beruntungnya, bukan itu yang terjadi. Vue mengimplementasi beberapa herustis pintar untuk memaksimalkan penggunaan kembali elemen DOM, jadi operasi mengganti sebuah array dengan array lain yang berisikan objek tumpang tindih sangat efisien.
Karena batasan-batasan pada JavaScript, Vue tidak bisa mendeteksi perubahan pada array berikut:
- Ketika kalian menentukan sebuah item dengan index, contohnya
vm.items[indexOfItem] = newValue
- Ketika kalian memodifikasi panjangnya sebuah array, contohnya
vm.items.length = newLength
Sebagai contoh:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // TIDAK bersifat reaktif
vm.items.length = 2 // TIDAK bersifat reaktif
Untuk mengatasi kekurangan 1, kedua kode berikut akan melakukan hal yang sama seperti vm.items[indexOfItem] = newValue
, tetapi juga akan memicu perubahan status pada sistem reaktifitas:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
Kalian juga bisa menggunakan metode instansi vm.$set
, yang mana adalah alias untuk Vue.set
global:
vm.$set(vm.items, indexOfItem, newValue)
Untuk mengatasi kekurangan 2, kalian bisa menggunakan splice
:
vm.items.splice(newLength)
Karena batasan dari modern JavaScript lagi, vue tidak bisa mendeteksi penambahan atau pengurangan properti. Contohnya:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` sekarang bersifat reactive
vm.b = 2
// `vm.b` tidak bersifat reactive
Vue tidak memperbolehkan menambahkan level-dasar properti reaktif secara dinamis ke instansi yang sudah dibuat. Tetapi, bisa untuk menambahkan properti reaktif ke objek terbungkus menggunakan metode Vue.set(object, key, value)
. Sebagai contoh:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
Kalian bisa menambahkan sebuah properti age
baru ke objek yang dibungkus userProfile
dengan:
Vue.set(vm.userProfile, 'age', 27)
Kalian juga bisa menggunakan metode instansi vm.$set
, dimana sebagai alias untuk Vue.set
yang global:
vm.$set(vm.userProfile, 'age', 27)
Terkadang kalian juga ingin menentukan angka sebagai properti baru ke objek yang sudah ada, contohnya menggunakan Object.assign()
atau _.extend()
. Di kasus seperti ini, kalian harus membuat sebuah objek baru dengan properti dari kedua objek. Jadi daripada membuat:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
Kalian ingin menambahkan properti properti baru, dengan:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
Terkadang kita ingin menampilkan versi array yang disaring atau disortir tanpa mengubah atau mengulang data yang asli. Pada kasus ini, kalian dapat membuat sebuah properti perhitungan yang mengembalikan array yang sudah di filter atau sortir.
Sebagai contoh:
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
Pada situasi dimana properti yang dihitung tidak bisa diakses (contohnya didalam perulangan v-for
), kalian bisa menggunakan:
<li v-for="n in even(numbers)">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-for
jusa bisa menggunakan sebuah integer. Pada kasus ini perulangan akan melakukan perulangan pada template sebanyak angka tersebut.
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
Hasil:
{% raw %}
Mirip dengan template v-if
, kalian juga bisa menggunakan tag <template>
dengan v-for
untuk me-render beberapa blok elemen. Contohnya:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
Catatan bahwa **tidak** direkomendasikan untuk menggunakan `v-if` dan `v-for` bersamaan. Berdasar pada [panduan style](/v2/style-guide/#Avoid-v-if-with-v-for-essential) untuk detail.
Ketika mereka ada pada node yang sama, v-for
memiliki prioritas lebih tinggi dibandingkan v-if
. Yang berarti v-if
akan dijalankan pada setiap perulangan secara terpisah. Hal ini bisa berguna ketika kalian ingin me-render node untuk sejumlah item, seperti dibawah ini:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
Diatas tadi hanya me-render todo yang tidak selesai.
Tetapi jika, yang kalian inginkan untuk melewatkan eksekusi perulangan, kalian bisa menempatkan v-if
pada elemen pembungkus (atau <template>
). Sebagai contoh:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
Bagian ini mengasumsikan pengetahuan tentang Komponen. Jangan ragu untuk melewatkannya dan kembali lain kali.
Kalian bisa menggunakan v-for
pada komponen kustom, seperti elemen normal lainnya:
<my-component v-for="item in items" :key="item.id"></my-component>
Pada 2.2.0+, ketika menggunakan
v-for
dengan sebuah komponen, sebuahkey
sekarang dibutuhkan.
Tetapi, hal ini tidak akan otomatis mengoper data ke komponen, karena komponen memiliki lingkup yang terbatas pada mereka sendiri. Agar mengoper data perulangan ke komponen, kita juga harus menggunakan props:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
Alasannya tidak otomatis memasukkan item
ke komponen adalah karena hal itu membuat komponen tergabung erat dengan bagimana v-for
bekerja. Menjadi eksplisit tentang dimana data datang membuat komponen tersebut dapat digunakan lagi pada situasi lain.
Berikut sebuah contoh lengkap daftar todo sederhana:
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Add</button>
</form>
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
</div>
Perhatikan attribut `is="todo-item"`. Hal ini sangat dibutuhkan untuk template DOM, karena hanya sebuah elemen `
- `. Hal tersebut berlaku sama dengan ``, tetapi sudah mengatasi browser error _parsing_ yang berpotensi. Lihat [Kekurangan Parsing Template DOM](components.html#DOM-Template-Parsing-Caveats) untuk mempelajari lebih lanjut.
- \ {{ title }}\ Remove\ \ ', props: ['title'] })
Vue.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button v-on:click="$emit(\'remove\')">Remove</button>\
</li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
{% raw %}
new Vue({ el: '#todo-list-example', data: { newTodoText: '', todos: [ { id: 1, title: 'Do the dishes', }, { id: 2, title: 'Take out the trash', }, { id: 3, title: 'Mow the lawn' } ], nextTodoId: 4 }, methods: { addNewTodo: function () { this.todos.push({ id: this.nextTodoId++, title: this.newTodoText }) this.newTodoText = '' } } }) </script> {% endraw %}