List rendering
Directory
Use v-for
to correspond an array to a set of elements
We can use ## The #v-for directive renders a list based on an array. The
v-for directive requires special syntax of the form
item in items, where
items is the source data array and
item is the target The
alias of the array element iterated over.
<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: In the
v-for block, we can access all the properties of the parent scope.
v-for also supports an optional second parameter, the index of the current item.
<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: You can also use
of instead of
in as the delimiter because it is more Syntax close to JavaScript iterators:
<div v-for="item of items"></div>
Using objects in v-for
You can also use
v-for to traverse the properties of an object.
<ul id="v-for-object" class="demo"> <li v-for="value in object"> {{ value }} </li> </ul>
new Vue({ el: '#v-for-object', data: { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } })Result: You can also provide the second parameter as the property name (that is, the key name):
<div v-for="(value, name) in object"> {{ name }}: {{ value }} </div>
You can also use the third parameter as the index:
<div v-for="(value, name, index) in object"> {{ index }}. {{ name }}: {{ value }} </div>
When traversing the object, you will press
Object.keys()
The results are traversed, but cannot guarantee that its results will be consistent under different JavaScript engines.
Maintenance status
When Vue is updating use v -for
When rendering a list of elements, it defaults to using the "update in place" strategy. If the order of the data items is changed, Vue will not move the DOM elements to match the order of the data items, but will update each element in place and ensure that they render correctly at each index position. This is similar to Vue 1.x’s track-by="$index"
.
This default mode is efficient, but is only suitable for list rendering output that does not rely on child component state or temporary DOM state (for example: form input values).
To give Vue a hint so that it can keep track of the identity of each node and thus reuse and reorder existing elements, you need to provide a unique key
attribute for each item:
<div v-for="item in items" v-bind:key="item.id"> <!-- 内容 --> </div>
It is recommended to provide the key
attribute when using v-for
whenever possible, unless traversing the output DOM content is very simple, or deliberately relying on the default behavior to gain performance promote.
Because it is a general mechanism for Vue to identify nodes, key
is not specifically related only to v-for
. As we'll see later in the guide, it also has other uses.
Do not use non-basic type values such as objects or arrays as the
key
ofv-for
. Please use a string or numeric value.
For more detailed usage of key
attribute, please go to the API documentation of key.
Array update detection
##Mutation method
Vue wraps the mutation methods of the listened array, so they will also trigger view updates. These wrapped methods include:push()
pop()
shift()
- ##unshift()
- splice()
- sort()
- reverse ()
array in the previous example. For example example1.items.push({ message: 'Baz' })
.
Replace array Mutation methods, as the name suggests, will change the original array on which these methods are called. In contrast, there are also non-mutating methods, such as You might think that this would cause Vue to discard the existing DOM and re-render the entire list. Fortunately, this is not the case. Vue implements some smart heuristics in order to maximize the reuse of DOM elements, so replacing the original array with an array containing the same elements is a very efficient operation. Notes Due to JavaScript limitations, Vue cannot detect the following Changes in the array: When you use the index to directly set an array item, for example: When you modify the length of the array, for example: For example: In order to solve the first type of problem, the following two methods can achieve the same effect as You can also use the To solve the second type of problem, you can use Vue cannot detect the addition or deletion of object properties: filter()
, concat()
and slice()
. They do not alter the original array, and always return a new array . When using the non-mutating approach, you can replace the old array with the new array: example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
vm.items[indexOfItem] = newValue
vm.items.length = newLength
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
vm.items[indexOfItem] = newValue
, and will also trigger status updates in the responsive system: // Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
vm.$set
instance method, which is an alias of the global method Vue.set
: vm.$set(vm.items, indexOfItem, newValue)
splice
: vm.items.splice(newLength)
##Object change detection considerations
Or due to JavaScript limitations, var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
Vue.set(object, propertyName, value) method. For example, for:
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } })you can add a new
age attribute to the nested
userProfile object:
Vue.set(vm.userProfile, 'age', 27)You can also use
vm.$set Instance method, it is just an alias of the global
Vue.set:
vm.$set(vm.userProfile, 'age', 27)Sometimes you may need to assign multiple new properties to an existing object, such as using
Object.assign() or
_.extend(). In this case, you should create a new object with the properties of both objects. So, if you want to add a new responsive attribute, instead of like this:
Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green' })you should do this:
vm.userProfile = Object.assign({}, vm.userProfile, { age: 27, favoriteColor: 'Vue Green' })
Display filtered/sorted results
Sometimes we want to display a filtered or sorted version of an array without actually Change or reset original data. In this case, you can create a computed property that returns a filtered or sorted array.
For example:
<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 }) } }
In cases where computed properties are not applicable (for example, in a nested v-for
loop) you can use a method:
<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 }) } }
Use value ranges in v-for
v-for
also accepts integers. In this case, it will repeat the template the corresponding number of times.
<div> <span v-for="n in 10">{{ n }} </span> </div>
Result:
##at<template> Using v-for
is similar to v-if
, you can also use v-for
's<template>
to loop through rendering a piece of content containing multiple elements. For example: <ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for is used together with v-if
Note that we
do notv-forrecommend using v-if and
When they are on the same node,v-for
on the same element. More details can be found in theStyle Guide
.
has a higher priority than v-if
, which means v-if
will be run repeatedly in each v-for
loop. This priority mechanism is useful when you only want to render nodes for some items, as follows:
The above code will only render unfinished todos. <li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
And if your purpose is to conditionally skip the execution of the loop, then you can place
v-if in the outer element (or <template>
)superior. For example:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
Use v-for
# on the component
##This part assumes that you already have knowledge about
just like you would on any normal element.components. You can also skip it and come back to it later. On a custom component, you can use
v-for
<my-component v-for="item in items" :key="item.id"></my-component>
As of version 2.2.0, keyis now required when using v-for
on a component.
However, no data will be automatically passed to the component because the component has its own independent scope. In order to pass the iteration data to the component, we need to use prop:
<my-component v-for="(item, index) in items" v-bind:item="item" v-bind:index="index" v-bind:key="item.id" ></my-component>
The reason why item
is not automatically injected into the component is that this will make the component different from v-for
's operations are tightly coupled. Clarifying the source of a component's data enables the component to be reused in other situations.
Here is a complete example of a simple todo list:
<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>
Note the
is="todo-item"
attribute here. This approach is very necessary when using DOM templates, because only the<li>
element within the<ul>
element will be regarded as valid content. This achieves the same effect as<todo-item>
, but can avoid some potential browser parsing errors. See DOM Template Parsing Instructions for more information.
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 = '' } } })