Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Vue.js 2.0 list rendering


May 07, 2021 Vue.js 2.0


Table of contents


Vue .js rendered from a 2.0 list

v-for

We render with the v-for instruction based on a list of options for an array. The v-for instruction requires a special syntax in the form of item in items, which are the source data array and the item is an alias for the array element iteration.

Basic usage

<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' }
    ]
  }
})

Results:

  • Foo
  • Bar

In the v-for block, we have full access to the parent scope property. v-for also supports an optional index of the second argument for 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' }
    ]
  }
})

Results:

  • Parent - 0 - Foo
  • Parent - 1 - Bar

You can also use of the alternative in as a separator because it is the syntax closest to the JavaScript iterator:

<div v-for="item of items"></div>

Template v-for

Like the v-if template, you can also render multiple element blocks with the v-for label. For example:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider"></li>
  </template>
</ul>

Object iteration v-for

You can also use v-for to iterate through the properties of an object.

<ul id="repeat-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
new Vue({
  el: '#repeat-object',
  data: {
    object: {
      FirstName: 'John',
      LastName: 'Doe',
      Age: 30
    }
  }
})

Results:

  • John
  • Doe
  • 30

You can also provide a second argument for the key name:

<div v-for="(value, key) in object">
  {{ key }} : {{ value }}
</div>

The third parameter is the index:

<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }} : {{ value }}
</div>

When traversing an object, it is traversed by object.keys(), but there is no guarantee that its results will be consistent under different JavaScript engines.

Integer iteration v-for

v-for can also take whole numbers. In this case, it repeats the template multiple times.

<div>
  <span v-for="n in 10">{{ n }}</span>
</div>

Results:

1 2 3 4 5 6 7 8 9 10

Components and v-for

Check out the Components section to learn about components. You can also skip this section and come back later to see it.

In custom components, you can use v-for like any normal element.

<my-component v-for="item in items"></my-component>

However, he cannot automatically pass data into a component because the component has its own independent scope. In order to pass iterative data into the component, we use props:

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index">
</my-component>

The reason item is not automatically injected into the component is because it makes the component tightly coupled to how v-for works. In some cases, identifying the source of the data can make components re-usable.

Here's a complete example of a simple todo list:

<div id="todo-list-example">
  <input
    v-model="newTodoText"
    v-on:keyup.enter="addNewTodo"
    placeholder="Add a todo"
  >
  <ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:title="todo"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>
Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">X</button>\
    </li>\
  ',
  props: ['title']
})
new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      'Do the dishes',
      'Take out the trash',
      'Mow the lawn'
    ]
  },
  methods: {
    addNewTodo: function () {
      this.todos.push(this.newTodoText)
      this.newTodoText = ''
    }
  }
})
  • Do the dishes
  • Take out the trash
  • Mow the lawn

key

When Vue.js is updating the list of rendered elements with v-for, it defaults to the "reusing in place" policy. I f the order of the data items is changed instead of moving the DOM elements to match the order of the data items, Vue simply reuses each element here and ensures that it displays each element that has been rendered under a specific index. This Vue 1.x-like track-by is "$index".

This default mode is valid, but applies only to list render outputs that do not depend on sub-component states or temporary DOM states such as form input values.

To give Vue a hint so that it can track the identity of each node, thereby reusing and reordering existing elements, you need to provide a unique key property for each item. T he ideal key value is that each item has a unique id. This particular property is equivalent to Vue 1.x's track-by, but it works like a property, so you need to bind dynamic values with v-bind (in short here):

<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

It is recommended that you use v-for whenever possible to provide key unless the iterative DOM content is simple enough, or if you are deliberately relying on the default behavior for performance improvements.

Because it is a common mechanism for identifying nodes in Vue, key is not particularly associated with v-for, and key has other uses, which we'll see in a later guide.

Array update detection

The method of variation

Vue contains a set of variation methods for observing arrays, so they also trigger view updates. These methods are as follows:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

You open the console and call the variation method with the items array in the previous example: example1.items.push ('message: 'Baz').

Reinvent the array

Mutation methods, as the name implies, change the original array called by these methods. I n contrast, there are non-variant methods, such as filter(), concat(), slice(). T hese do not change the original array, but always return a new array. When using a non-variation method, you can replace the old array with a new one:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

You might think this will cause Vue to discard the existing DOM and re-render the entire list. F ortunately, this is not the case. Vue implements some intelligent heuristics to maximize DOM element reuse, so replacing the original array with an array of the same elements is a very efficient operation.

Precautions

Due to JavaScript restrictions, Vue cannot detect arrays of the following changes:

  1. When you set the index of an item directly, for example: vm.items (indexOfItem) - newValue
  2. When you modify the length of an array, for example: vm.items.length s newLength

To avoid the first case, the following two ways will achieve effects like vm.items (indexOfItem) and newValue, and will also trigger a status update:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice`
example1.items.splice(indexOfItem, 1, newValue)

To avoid the second scenario, use splice:

example1.items.splice(newLength)

Displays the filter/sort results

Sometimes we want to display a filtered or sorted copy of an array without actually changing or resetting the original data. In this case, you can create a calculated 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
    })
  }
}

Alternatively, you can use the method method if the calculated property does not apply (for example, in a nested v-for loop):

<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
    })
  }
}