Работа с циклами в фреймворке Vue


Пусть теперь в data у нас есть элемент items, который содержит внутри себя массив с некоторыми данными:

let app = new Vue({
el: '#app',
data: {
items: ['a', 'b', 'c', 'd', 'e'],
},
});
Давайте сделаем список ul, внутри которого разместим каждый элемент нашего массива items в отдельную li.

Очевидно, что нам нужен какой-то цикл, который сделает это за нас. Во Vue такой цикл делается следующим образом: <li v-for="item in items">.

Давайте разберем, что тут происходит. Атрибут v-for запускает цикл, строка item in items указывает на то, что мы будем перебирать массив items, а каждый элемент этого массива будет ложиться в переменную item.

В результате эта строка: <li v-for="item in items"> - сделает столько тегов li, сколько раз прокрутится цикл.

Внутри li будет доступна переменная item, в которой каждой раз будет содержаться новый элемент массива. Мы можем вывести ее содержимое с помощью фигурных скобок, вот так: {{ item }}. Эта переменная может иметь любое название, которое мы захотим - как назовем - так и будем пользоваться (то есть item это не какое-то обязательное слово).

Итого полный код для li будет выглядеть так:

<li v-for="item in items">{{ item }}</li>
Давайте соберем все вместе и запустим:

let app = new Vue({
el: '#app',
data: {
items: ['a', 'b', 'c', 'd', 'e'],
},
});
<div id="app">
<ul>
<li v-for="item in items">{{ item }}</li>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
</ul>
</div>
Итак, если у нас есть массив с данными, мы можем перебрать его в цикле и сформировать нужный нам HTML код прямо на лету.

Варианты циклов
Иногда кроме элементов массива, мы хотели бы получить доступ еще и к ключам. Для этого вместо item in items следует написать (item, index) in items - тогда в переменную item будут попадать элементы массива, а в index - их ключи. Вместо index вы можете использовать любое другое название, как вам удобно.

Давайте попробуем:

let app = new Vue({
el: '#app',
data: {
items: ['a', 'b', 'c', 'd', 'e'],
},
});
<div id="app">
<ul>
<li v-for="(item, index) in items">{{ item }} - {{ index }}</li>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>a - 0</li>
<li>b - 1</li>
<li>c - 2</li>
<li>d - 3</li>
<li>e - 4</li>
</ul>
</div>

Циклы и объекты
Циклом v-for можно перебирать не только массивы, но и объекты. Синтаксис полностью аналогичный.

Пусть у нас в users хранится объект с именами работников и их зарплатами:

let app = new Vue({
el: '#app',
data: {
users: {user1: '300$', user2: '400$', user3: '500$'},
},
});
Давайте выведем на экран их зарплаты в виде списка ul:

<div id="app">
<ul>
<li v-for="value in users">{{ value }}</li>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>300$</li>
<li>400$</li>
<li>500$</li>
</ul>
</div>
Можно также выводить одновременно и ключи, и значения. Давайте сделаем это:

<div id="app">
<ul>
<li v-for="(value, key) in users">{{ key }} - {{ value }}</li>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>user1 - 300$</li>
<li>user2 - 400$</li>
<li>user3 - 500$</li>
</ul>
</div>
Если вам нужны еще и порядковые номера элементов в объекте - сделайте третью переменную и номера будут попадать туда:

<div id="app">
<ul>
<li v-for="(value, key, index) in users">
{{ key }} - {{ value }} - {{ index }}
</li>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>user1 - 300$ - 0</li>
<li>user2 - 400$ - 1</li>
<li>user3 - 500$ - 2</li>
</ul>
</div>

Многомерные массивы и циклы
Давайте попробуем цикл на более сложных конструкциях.

Пусть у нас в users хранится массив, элементами которого являются объекты с именами работников и их зарплатами:

let app = new Vue({
el: '#app',
data: {
users: [
{name: 'user1', salary: '300$'},
{name: 'user2', salary: '400$'},
{name: 'user3', salary: '500$'},
],
},
});
Если запустить такой цикл - <li v-for="user in users"> - то в user каждый раз будет попадать объект с работником: сначала {name: 'user1', salary: '300$'}, потом {name: 'user2', salary: '400$'} и так далее.

То есть в user.name будет лежать имя работника, а в user.salary - его зарплата.

Давайте запустим наш код:

let app = new Vue({
el: '#app',
data: {
users: [
{name: 'user1', salary: '300$'},
{name: 'user2', salary: '400$'},
{name: 'user3', salary: '500$'},
],
},
});
<div id="app">
<ul>
<li v-for="user in users">
{{ user.name }} - {{ user.salary }}
</li>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>user1 - 300$</li>
<li>user2 - 400$</li>
<li>user3 - 500$</li>
</ul>
</div>

Директива v-for и тег template
Представим себе следующую ситуацию: в цикле нам нужно делать не один тег li, на несколько, например мы хотели бы, чтобы в каждой итерации цикла повторялись вот эти li (две сразу):

<li>{{ item }}</li>
<li class="divider"></li>
Нюанс в том, что когда у нас был один тег li - мы задавали директиву v-for ему. Но что делать, если у нас два тега li?

В этом случае можно объединить наши теги в какой-нибудь другой тег, например, в div, и задать директиву v-for ему:

<ul>
<div v-for="item in items">
<li>{{ item }}</li>
<li class="divider"></li>
</div>
</ul>
Проблема, однако, в том, что в теге ul не могут располагаться другие теги, кроме li. Да и даже, если бы в теге ul разрешено было бы размещать другие теги, все равно это было бы не удобно, так как могло бы сломать нашу верстку (нам не нужен этот div для верски, однако, пришлось бы его добавить).

Для решения проблемы в фремйворке Vue предусмотрен тег <template>. Данный тег выполняет объединяющую функцию - в нем можно группировать теги, задавая им общую директиву v-for, и при этом верстка, полученная в результате, не будет содержать никаких лишний тегов (то есть после цикла все теги <template> исчезнут из верстки).

Итак, добавим тег <template>:

<ul>
<template v-for="item in items">
<li>{{ item }}</li>
<li class="divider"></li>
</template>
</ul>
Давайте напишем полный код и запустим его:

let app = new Vue({
el: '#app',
data: {
items: ['a', 'b', 'c', 'd', 'e'],
},
});
<div id="app">
<ul>
<template v-for="item in items">
<li>{{ item }}</li>
<li class="divider"></li>
</template>
</ul>
</div>
Результатом этого кода будет следующий HTML:

<div id="app">
<ul>
<li>a</li>
<li class="divider"></li>
<li>b</li>
<li class="divider"></li>
<li>c</li>
<li class="divider"></li>
<li>d</li>
<li class="divider"></li>
<li>e</li>
<li class="divider"></li>
</ul>
</div>