логотип PurpleSchool
логотип PurpleSchool

Организация циклов и итераций во Vue

Автор

Анна Жукова

Введение

В работе с фронтендом вы часто сталкиваетесь с необходимостью отображать списки данных и динамически их изменять. Если вы используете Vue, то для организации циклов и итераций у вас есть эффективные встроенные инструменты, которые делают обработку массивов и объектов на шаблоне предельно простой и гибкой. В этой статье я расскажу, как в Vue правильно создавать циклы, разбирать массивы и объекты, использовать ключи для оптимизации рендеринга и что делать при работе со сложными и вложенными структурами данных.

Директива v-for — основа организации циклов во Vue

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

Основной синтаксис v-for

Смотрите, базовый синтаксис v-for выглядит так:

<li v-for="item in items" :key="item.id">
  {{ item.name }}
</li>

Здесь:

  • items – массив из вашего компонента
  • item – текущий элемент массива на каждой итерации
  • Атрибут :key — помогает Vue оптимизировать повторный рендеринг элементов (ключи обязательны, если список будет динамически меняться)

Итерация по массивам

Давайте разберемся на примере:

<template>
  <ul>
    <li v-for="(fruit, index) in fruits" :key="index">
      {{ index }}: {{ fruit }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      fruits: ['Яблоко', 'Груша', 'Апельсин']
    }
  }
}
</script>
  • Рендерит список фруктов с индексами.
  • Параметр index — текущий индекс итерации (начинается с 0).

Итерация по объектам

Если ваши данные представлены объектом, v-for позволяет пройтись по его ключам, значениям и парам ключ-значение.

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

<script>
export default {
  data() {
    return {
      user: {
        name: 'Иван',
        age: 30,
        city: 'Москва'
      }
    }
  }
}
</script>
  • key — текущий ключ объекта (например, name, age)
  • value — значение этого ключа

Использование индексов и вложенных значений

Если нужно получить и значение, и индекс, используйте следующий синтаксис:

<li v-for="(item, idx) in items" :key="idx">
  {{ idx }} — {{ item }}
</li>

Часто индексы применяют только для статических или простых списков. Если список изменяется (добавление, удаление), используйте уникальные ключи, например, идентификаторы из объекта.

Вложенные циклы — перебираем массивы внутри массивов

Вам может понадобиться пройтись по списку внутри другого списка (например, список категорий, каждая из которых содержит массив товаров):

<template>
  <div v-for="category in categories" :key="category.id">
    <h3>{{ category.name }}</h3>
    <ul>
      <li v-for="product in category.products" :key="product.id">
        {{ product.title }}
      </li>
    </ul>
  </div>
</template>
  • Внешний цикл — перебор категорий
  • Внутренний цикл — перебор товаров внутри категории

Обратите внимание, что каждому элементу обязательно нужен свой уникальный ключ на каждом уровне вложенности.

Передача других параметров в v-for

Иногда бывает удобно передать не только индекс, но и весь элемент как объект. Вот пример:

<li 
  v-for="(user, idx) in users" 
  :key="user.id"
  :class="{ active: idx === selectedIndex }"
>
  {{ user.name }}
</li>
  • Здесь каждый элемент списка дополнительно получает класс active, если его индекс совпадает с выбранным элементом.

Итерация по range (диапазону чисел)

В отличие от некоторых других фреймворков, у Vue нет встроенного метода range в шаблоне, но такую функциональность легко реализовать через вычисляемое свойство:

<template>
  <li v-for="n in range" :key="n">
    Итерация {{ n }}
  </li>
</template>

<script>
export default {
  computed: {
    range() {
      // Выведет числа от 1 до 5
      return Array.from({ length: 5 }, (v, k) => k + 1)
    }
  }
}
</script>

Для динамических диапазонов просто меняйте длину массива согласно нужной логике.

Оптимизация рендеринга с помощью ключа (key)

Vue рекомендует всегда указывать уникальный ключ через :key в v-for. Ключ используется внутренним механизмом виртуального DOM для быстрого переиспользования и оптимального обновления элементов при изменении массива.

Пример ключей с идентификаторами

<li v-for="item in items" :key="item.id">
  {{ item.name }}
</li>
  • Если идентификаторы отсутствуют, используйте индексы (:key="index"), но это допустимо только для статических списков.
  • При динамической модификации массива (добавлении, удалении, перемещении элементов) ключи должны быть уникальными и неизменяемыми.

Ошибки использования ключей

Обратите внимание: если в качестве ключа использовать значения, которые могут повторяться или изменяться (например, сам объект или его нестабильное поле), Vue может неправильно отслеживать элементы при обновлении.

Правильный способ:

<li v-for="user in users" :key="user.email">
  {{ user.name }}
</li>

Неправильный способ (может привести к багам):

<li v-for="user in users" :key="user">
  {{ user.name }}
</li>

Работа с динамическими изменениями данных

В повседневной разработке чаще всего приходится работать с изменяемыми структурами — добавлять, удалять или сортировать элементы списка.

Добавление и удаление элементов

Vue автоматически обновляет DOM, если вы обновляете массив:

this.items.push({ name: 'Новый элемент', id: 123 })
// Новый элемент появится в DOM

this.items.splice(1, 1)
// Второй элемент будет удален в DOM

Но важно соблюдать два правила:

  • Любые мутации должны происходить через методы реактивного массива (push, pop, shift, splice и другие).
  • Никогда не присваивайте полностью новый массив частью старого без реактивного трекера, иначе Vue может не заметить обновления.

Например, если сделать:

this.items = [{ name: 'A' }, { name: 'B' }]

Vue отслеживает это как полную замену всего массива.

Сортировка и фильтрация данных

Если нужно отобразить отсортированный или отфильтрованный список, используйте вычисляемые свойства:

<template>
  <li v-for="item in sortedItems" :key="item.id">
    {{ item.name }}
  </li>
</template>

<script>
export default {
  data() {
    return {
      items: [/* массив объектов */]
    }
  },
  computed: {
    sortedItems() {
      // Возвращает новый отсортированный массив, не меняя исходный
      return this.items.slice().sort((a, b) => a.name.localeCompare(b.name))
    }
  }
}
</script>

Аналогично реализуется и фильтрация:

<li v-for="item in filteredItems" :key="item.id">
  {{ item.name }}
</li>
computed: {
  filteredItems() {
    return this.items.filter(item => item.active)
  }
}

Организация циклов во Vue 3 и Composition API

Если вы работаете с Vue 3, вместо опции data часто применяются функции setup и реактивные переменные:

<script setup>
import { ref, computed } from 'vue'

const items = ref([
  { id: 1, name: 'A' },
  { id: 2, name: 'B' }
])

const sortedItems = computed(() => {
  return items.value.slice().sort((a, b) => a.name.localeCompare(b.name))
})
</script>

<template>
  <li v-for="item in sortedItems" :key="item.id">
    {{ item.name }}
  </li>
</template>

Здесь все те же правила — уникальные ключи, отдельные computed для сортировки/фильтрации.

Отображение пустых состояний

При итерации по массиву часто требуется обработать случай, если список пуст. Сделать это можно с помощью условных конструкций:

<ul>
  <li v-for="item in items" :key="item.id">
    {{ item.name }}
  </li>
  <li v-if="items.length === 0">Список пуст</li>
</ul>
  • Если массив items пуст — отобразится "Список пуст".
  • Если не пуст — отобразится список элементов.

Ещё один способ (через computed):

<template>
  <div v-if="hasItems">
    <li v-for="item in items" :key="item.id">{{ item.name }}</li>
  </div>
  <div v-else>
    Нет данных
  </div>
</template>
computed: {
  hasItems() {
    return this.items && this.items.length > 0
  }
}

Использование v-for с шаблонами template

Иногда приходится рендерить сразу несколько узлов на одну итерацию. Для этого используйте тег <template>:

<template v-for="item in items" :key="item.id">
  <div>{{ item.name }}</div>
  <span v-if="item.price">Цена: {{ item.price }}</span>
</template>
  • Контейнер <template> не попадает в итоговую разметку, но позволяет описывать сразу несколько элементов для одной итерации.

Особенности и best practices использования v-for

Никогда не используйте один и тот же v-for и v-if на одном элементе

Это распространённая ошибка — нельзя писать:

<li v-for="item in items" v-if="item.visible" :key="item.id">
  {{ item.name }}
</li>

Вместо этого фильтруйте данные заранее (через computed) и передавайте уже отфильтрованный массив в v-for. Иначе возможны баги в рендеринге и неочевидное поведение.

Не используйте индексы как ключи без необходимости

Лучше всегда использовать уникальные идентификаторы объектов. Исключение — когда список гарантированно статичен и не изменяется, но такие сценарии редки.

Никогда не мутируйте объекты вне реактивных методов

Если вы добавляете поля объекту или удаляете их, убедитесь, что Vue сможет отследить эти изменения. Для этого во Vue 2 используйте методы Vue.set и Vue.delete, во Vue 3 это не требуется.

Генерация ключей внутри шаблона запрещена

Не используйте внутри :key выражений, генерирующих новые уникальные значения на каждом рендере (например, Date.now() или Math.random()), ключ должен быть стабильным и однозначно идентифицировать элемент.

Заключение

Организация циклов и итераций во Vue — один из важнейших аспектов динамического отображения данных. Использование директивы v-for позволяет быстро и удобно рендерить списки любых типов — от простых массивов и объектов до массивов с вложенностью и различных динамических структур. Для оптимальной производительности и предсказуемости работы приложения всегда используйте уникальные ключи, фильтруйте и сортируйте данные через вычисляемые свойства, а все изменения в данных производите реактивными методами. Такой подход сделает ваш код стабильным, поддерживаемым и легко модифицируемым.

Частозадаваемые технические вопросы по теме статьи и ответы на них

Как организовать итерацию по множеству свойств объекта с вложенностью различного уровня?

Для сложных объектов используйте рекурсивные компоненты. Передавайте текущий уровень свойств как prop, а внутри компонента используйте v-for для прохода по свойствам. Для каждого значения проверяйте, является ли оно объектом — если да, вызывайте компонент рекурсивно.

Можно ли применять v-for к пользовательским компонентам?

Да, можно. Например: vue <UserCard v-for="user in users" :key="user.id" :user="user" /> Каждая итерация создаёт отдельный экземпляр компонента, принимающего текущий элемент данных через пропсы.

Как эффективно обновлять списки при загрузке данных по частям (пагинация)?

Загружайте очередную страницу данных и добавляйте новые элементы к существующему массиву через push или concat, чтобы сохранить реактивность массива: js this.items = this.items.concat(новые_элементы) Убедитесь, что ключи уникальны для всех элементов.

Почему иногда после удаления элементов из массива остаётся «дырка»?

Если удалять элемент с помощью delete, Vue не отслеживает это реактивно. Используйте splice: js this.items.splice(index, 1) Это гарантирует правильное обновление DOM.

Как реализовать вложенные фильтры или сортировку внутри v-for?

Вычисляемое свойство возвращает двумерный (или более) отфильтрованный или отсортированный массив, и каждый уровень итерации работает строго с подготовленными данными: js computed: { filteredCategories() { return this.categories.map(category => ({ ...category, products: category.products.filter(p => p.available) })) } } Теперь вы итерируете только по нужным значениям.

Стрелочка влевоИспользование компонентов datepicker в Vue для выбора датКак работает компиляция Vue CoreСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueИнструкция по установке и компонентам Vue sliderРабота с таблицами во Vue через TanStackУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveЗагрузка и управление состоянием загрузки в VueИспользование query-параметров и их обработка в маршрутах VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueСоздание и использование UI Kit для Vue приложенийУправление пользователями и их данными в Vue приложенияхТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний