List Rendering
Vue.createApp({
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}).mount('#array-rendering')
Result:
See the Pen v-for with Array by Vue () on CodePen.
Inside v-for
blocks we have full access to parent scope properties. v-for
also supports an optional second argument for the index of the current item.
<ul id="array-with-index">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
Vue.createApp({
data() {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}).mount('#array-with-index')
Result:
See the Pen by Vue (@Vue) on .
You can also use of
as the delimiter instead of in
, so that it is closer to JavaScript’s syntax for iterators:
<div v-for="item of items"></div>
v-for with an Object
You can also use v-for
to iterate through the properties of an object.
<ul id="v-for-object" class="demo">
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
Vue.createApp({
data() {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}).mount('#v-for-object')
Result:
See the Pen by Vue (@Vue) on .
You can also provide a second argument for the property’s name (a.k.a. key):
See the Pen v-for with Object and key by Vue () on CodePen.
And another for the index:
<li v-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>
See the Pen by Vue (@Vue) on .
When iterating over an object, the order is based on the enumeration order of Object.keys()
, which isn’t guaranteed to be consistent across JavaScript engine implementations.
Maintaining State
When Vue is updating a list of elements rendered with v-for
, by default it uses an “in-place patch” strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index.
This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values).
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key
attribute for each item:
<!-- content -->
</div>
It is recommended to provide a key
attribute with v-for
whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.
Since it’s a generic mechanism for Vue to identify nodes, the key
also has other uses that are not specifically tied to v-for
, as we will see later in the guide.
Note
Don’t use non-primitive values like objects and arrays as v-for
keys. Use string or numeric values instead.
For detailed usage of the key
attribute, please see the .
Vue wraps an observed array’s mutation methods so they will also trigger view updates. The wrapped methods are:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
You can open the console and play with the previous examples’ items
array by calling their mutation methods. For example: example1.items.push({ message: 'Baz' })
.
Replacing an Array
Mutation methods, as the name suggests, mutate the original array they are called on. In comparison, there are also non-mutating methods, e.g. filter()
, concat()
and slice()
, which do not mutate the original array but always return a new array. When working with non-mutating methods, you can replace the old array with the new one:
example1.items = example1.items.filter(item => return item.message.match(/Foo/))
You might think this will cause Vue to throw away the existing DOM and re-render the entire list - luckily, that is not the case. Vue implements some smart heuristics to maximize DOM element reuse, so replacing an array with another array containing overlapping objects is a very efficient operation.
Displaying Filtered/Sorted Results
Sometimes we want to display a filtered or sorted version of an array without actually mutating or resetting the original data. In this case, you can create a computed property that returns the filtered or sorted array.
data() {
return {
numbers: [ 1, 2, 3, 4, 5 ]
}
},
computed: {
evenNumbers() {
return this.numbers.filter(number => number % 2 === 0)
}
}
In situations where computed properties are not feasible (e.g. inside nested v-for
loops), you can use a method:
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)">{{ n }}</li>
</ul>
v-for with a Range
v-for
can also take an integer. In this case it will repeat the template that many times.
<div id="range" class="demo">
</div>
Result:
See the Pen by Vue (@Vue) on .