Vue.jsJuniorTechnical

В чём разница между v-if, v-else-if, v-else и v-show?

v-if полностью добавляет/удаляет элемент из DOM, v-show только переключает display: none. v-if дешевле при частом отсутствии элемента, v-show — при частых переключениях видимости.

v-if: условный рендеринг

Директива v-if полностью монтирует и размонтирует компонент/элемент. При false элемент отсутствует в DOM.

<template>
  <div v-if="isLoggedIn">
    <UserProfile />
  </div>
  <div v-else>
    <LoginForm />
  </div>
</template>

При переходе false → true Vue создаёт элемент с нуля, запускает хуки onMounted, делает запросы данных. При true → false — вызывает onUnmounted, освобождает ресурсы.

v-else-if и v-else

Должны следовать непосредственно за v-if или v-else-if на соседнем элементе:

<p v-if="status === 'loading'">Загрузка...</p>
<p v-else-if="status === 'error'">Ошибка: {{ errorMsg }}</p>
<p v-else>Готово</p>

v-show: CSS-переключение

Директива v-show всегда рендерит элемент в DOM, управляя только инлайн-стилем display:

<div v-show="isMenuOpen">
  <nav>...</nav>
</div>
<!-- Результат при false: <div style="display: none;">...</div> -->

Хуки жизненного цикла не вызываются при переключении v-show.

Когда что использовать

  • v-if — когда элемент редко отображается (условие ложно большую часть времени) или несёт дорогостоящую инициализацию. Пример: блок для авторизованных пользователей.
  • v-show — когда элемент часто переключается (dropdown-меню, аккордеон, tooltips). Первичная загрузка страницы дороже, но переключения мгновенны.

Использование с <template>

v-if можно применять к <template> — невидимой обёртке для нескольких элементов:

<template v-if="hasData">
  <h2>Результаты</h2>
  <ul>
    <li v-for="item in items" :key="item.id">{{ item.name }}</li>
  </ul>
</template>

v-show не работает с <template> — применяйте только к реальным элементам.

Приоритет v-if vs v-for

В Vue 3 v-if имеет более высокий приоритет, чем v-for на одном элементе (в Vue 2 — наоборот). Не смешивайте их:

<!-- Плохо: v-if выполняется раньше v-for, item недоступен -->
<li v-for="item in list" v-if="item.active">{{ item.name }}</li>

<!-- Хорошо: фильтрация через computed -->
<li v-for="item in activeItems" :key="item.id">{{ item.name }}</li>

Подводные камни

  • v-show не работает с тегом <template> и с компонентами, у которых display переопределён в CSS как !important.
  • Компоненты под v-if уничтожаются при скрытии — локальное состояние (введённые данные в форме) теряется. Используйте v-show или выносите состояние выше.
  • Переход между v-else-ветками с одинаковым тегом без key — Vue переиспользует DOM-узел. Добавьте key чтобы принудить пересоздание.
  • Тяжёлые компоненты под v-show рендерятся при загрузке страницы даже если скрыты — это может замедлить LCP. Используйте v-if + <Suspense> для отложенного рендера.
  • Смешение v-if и v-for на одном элементе — признанный антипаттерн; всегда разносите их по разным уровням.

Common mistakes

  • Использовать v-show для одноразового условного блока, и зря держать DOM.
  • Использовать v-if для часто мигающего тултипа.
  • Совмещать v-if и v-for на одном узле.
  • Считать, что v-show улучшает SEO больше, чем v-if — для поисковика оба возвращают разметку, важна семантика.

What the interviewer is testing

  • Понимает разницу «в DOM/нет в DOM».
  • Знает, что v-show нельзя применить к <template>.
  • Может назвать сценарии для каждого.
  • Не путает поведение v-else-if с обычным if-else в шаблоне.

Sources

Related topics