Vue

Условия и списки: v-if, v-show, v-for

Лента уведомлений в почтовом клиенте показывает список писем, скрывает блок 'входящих нет', когда список не пуст, и держит наготове свёрнутую панель фильтров, которую пользователь дёргает десятки раз за сессию. Список рисуется через v-for, пустое состояние - через v-if, а панель, которую часто переключают, - через v-show, потому что её дешевле прятать стилем, чем создавать заново. Неверный выбор между v-if и v-show либо тормозит частые переключения, либо держит в DOM лишние тяжёлые узлы.

  • Список товаров или писем через v-for с уникальным key по id для корректного переиспользования узлов
  • Пустое состояние 'ничего не найдено' через v-if, когда результат фильтрации пуст
  • Часто переключаемая боковая панель или таб через v-show: переключение видимости без пересоздания DOM
  • Условный рендер по роли: блок администратора через v-if, чтобы вообще не попасть в DOM обычного пользователя

Предварительные знания

  • Шаблонный синтаксис: интерполяция и привязка атрибутов через v-bind
  • Понимание реактивного состояния (ref) как источника данных для шаблона
  • Базовая работа с массивами и объектами в JavaScript

v-if против v-show

Обе директивы управляют видимостью, но по-разному. v-if - настоящий условный рендеринг: при ложном условии элемент и его дочерние компоненты не создаются вовсе, их нет в DOM. v-show всегда рендерит элемент и переключает только CSS-свойство display. Отсюда правило: v-if дешевле при первом рендере (не строит скрытое), v-show дешевле при частых переключениях (не пересоздаёт).

Критерийv-ifv-show
Элемент в DOM при falseОтсутствуетПрисутствует (display:none)
Стоимость первого рендераНизкая, если условие falseВысокая, рендерится всегда
Стоимость переключенияВысокая, создание/удалениеНизкая, смена CSS
Поддержка v-elseДаНет

Эмпирика выбора: если переключение редкое или ветка тяжёлая и часто не нужна - v-if. Если элемент переключают часто (вкладки, аккордеон, тултип) - v-show, чтобы не платить за пересоздание DOM каждый раз.

Боковая панель фильтров открывается и закрывается десятки раз за сессию. Какая директива уместнее и почему?

v-for: массивы, объекты, диапазоны

v-for перебирает источник и рендерит элемент на каждую запись. Для массива доступны элемент и индекс: v-for="(item, index) in items". Для объекта - значение, ключ и индекс: v-for="(value, key) in obj". Для диапазона v-for="n in 5" даёт числа от 1 до 5, что удобно для рейтинга-звёздочек или пагинации.

Для отрисовки группы элементов по условию без лишней обёртки используют тег template с v-for или v-if: он не создаёт реальный DOM-узел, а служит невидимым контейнером для директивы.

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

Как через v-for получить значение и ключ при переборе объекта { name: 'Anna', age: 30 }?

key: зачем и почему не индекс

Атрибут key даёт Vue стабильную идентичность каждого элемента списка. По нему Vue понимает, какой узел переиспользовать, какой создать, а какой удалить при изменении массива. Без стабильного key Vue вынужден угадывать соответствие старых и новых элементов, что приводит к перепутанному состоянию: введённый текст или активный чекбокс остаются не у той строки.

Почему индекс ломается

Стабильный id вместо индекса сохраняет привязку состояния DOM к правильной записи

Список из трёх задач с key по индексу 0,1,2. Пользователь отметил чекбокс у второй задачи, и тут в начало вставляется новая. Теперь индексы сдвинулись: бывшая вторая задача стала третьей, но Vue видит, что под key=1 всё ещё есть элемент, и переиспользует старый DOM с уже стоящей галочкой - галочка оказывается не у той задачи.

Индекс как key допустим только для статичного списка, который никогда не переупорядочивается, не фильтруется и не меняет длину в середине. Как только возможны вставки, удаления или сортировка - нужен стабильный идентификатор записи.

Почему использование индекса массива как key опасно при вставке элемента в начало списка?

Почему v-if и v-for не на одном элементе

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

Предпочтительнее фильтровать список заранее в computed: шаблон остаётся чистым, фильтрация кэшируется и пересчитывается только при изменении источника, а не на каждый рендер.

Почему в Vue 3 не стоит ставить v-if и v-for на один элемент для фильтрации списка?

Связь с другими темами

Условия и списки - ядро шаблонов. Дальше они соединяются с другими директивами:

  • Обработка событий — На каждый элемент списка вешают обработчик действия, передавая в него данные строки
  • Реактивность изнутри — Корректное обновление списка по key опирается на отслеживание изменений реактивного массива

Итог

  • v-if добавляет и удаляет элемент из DOM по условию; ложная ветка не существует в разметке вовсе
  • v-show всегда держит элемент в DOM и переключает только CSS display, что дешевле при частых переключениях
  • v-for перебирает массивы, объекты и диапазоны; каждому элементу нужен стабильный уникальный key
  • key по индексу ломается при вставке и удалении в середине; ключом берут стабильный id записи
  • v-if и v-for не ставят на один элемент: их приоритет неоднозначен, перебор оборачивают в template или фильтруют заранее

Связанные уроки

  • vue-14-event-handling — v-for и обработка событий часто работают вместе: список элементов с кнопкой действия на каждом
  • vue-18-reactivity-deep — key в v-for и отслеживание изменений массива опираются на реактивную систему, разбираемую глубже там
Условия и списки: v-if, v-show, v-for

0

1

Войти