← Vue 3/v-if, v-else-if, v-else и v-show#313 из 430← ПредыдущийСледующий →+20 XP
Полезно по теме:Гайд: React или VueПрактика: Vue setТермин: Composition APIТема: Vue 3 и Composition API
← НазадДалее →

v-if, v-else-if, v-else и v-show

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

Директива v-if полностью добавляет или удаляет элемент из DOM в зависимости от условия. Когда условие ложно, элемент не существует в DOM вообще.

<template>
  <div v-if="isLoggedIn">
    <p>Добро пожаловать, {{ username }}!</p>
    <button @click="logout">Выйти</button>
  </div>
</template>

<script setup>
const isLoggedIn = ref(false)
const username = ref('Алексей')
</script>

Цепочка v-if / v-else-if / v-else

Работает аналогично обычным условным операторам JavaScript:

<template>
  <p v-if="score >= 90">Отлично!</p>
  <p v-else-if="score >= 70">Хорошо</p>
  <p v-else-if="score >= 50">Удовлетворительно</p>
  <p v-else">Нужно подтянуть знания</p>
</template>

Важно: v-else-if и v-else должны идти сразу после элемента с v-if — без других элементов между ними.

v-if на элементе template

Если нужно условно скрыть группу элементов без обёртки в лишний <div>, используется тег <template> — он не рендерится в DOM:

<template v-if="isAdmin">
  <h2>Панель администратора</h2>
  <p>Здесь управление пользователями</p>
  <AdminTable />
</template>

v-show: скрытие через CSS

Директива v-show работает иначе: элемент всегда находится в DOM, но при ложном условии к нему применяется display: none:

<template>
  <div v-show="isVisible">
    Этот блок скрыт через display: none
  </div>
</template>

<script setup>
const isVisible = ref(true)
</script>

Сравнение v-if и v-show

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

Когда использовать v-show: когда элемент часто переключается (например, выпадающее меню, модальное окно которое открывают/закрывают много раз).

Когда использовать v-if: когда условие редко меняется, или при false рендеринг элемента не нужен вообще (например, панель администратора, которую видит лишь малый процент пользователей).

Важная деталь: v-if ленив

Если v-if изначально равно false, Vue вообще не рендерит элемент — не создаёт компонент, не запускает его хуки жизненного цикла. Это важно при работе с тяжёлыми компонентами:

<!-- HeavyChart создастся только когда showChart = true -->
<HeavyChart v-if="showChart" :data="chartData" />

С v-show компонент создастся при первом рендере страницы, даже если он скрыт.

Примеры

Эмуляция v-if и v-show: разница между удалением из DOM и скрытием через display:none

// Сравниваем поведение v-if (удаление из DOM) и v-show (display: none)

// Псевдо-DOM для демонстрации
class PseudoDOM {
  constructor() {
    this.elements = new Map()
    this.parent = { children: [] }
  }

  createElement(tag, id) {
    const el = { tag, id, style: {}, inDOM: false }
    this.elements.set(id, el)
    return el
  }

  // v-if: добавляем/удаляем элемент из DOM
  vIf(el, condition) {
    if (condition && !el.inDOM) {
      this.parent.children.push(el)
      el.inDOM = true
      console.log(`[v-if] <${el.tag}#${el.id}> ДОБАВЛЕН в DOM`)
    } else if (!condition && el.inDOM) {
      this.parent.children = this.parent.children.filter(c => c !== el)
      el.inDOM = false
      console.log(`[v-if] <${el.tag}#${el.id}> УДАЛЁН из DOM`)
    } else {
      console.log(`[v-if] <${el.tag}#${el.id}> без изменений (condition=${condition})`)
    }
  }

  // v-show: меняем только display
  vShow(el, condition) {
    if (!el.inDOM) {
      this.parent.children.push(el)
      el.inDOM = true
    }
    el.style.display = condition ? '' : 'none'
    console.log(`[v-show] <${el.tag}#${el.id}> display="${el.style.display || 'block'}" (в DOM: да)`)
  }

  printDOM() {
    console.log('\nТекущее состояние DOM:')
    if (this.parent.children.length === 0) {
      console.log('  (пусто)')
    }
    this.parent.children.forEach(el => {
      const display = el.style.display === 'none' ? ' [скрыт: display:none]' : ''
      console.log(`  <${el.tag} id="${el.id}"${display}>`)
    })
  }
}

const dom = new PseudoDOM()
const panel = dom.createElement('div', 'admin-panel')
const menu = dom.createElement('nav', 'dropdown-menu')

console.log('=== v-if: переключаем панель администратора ===')
dom.vIf(panel, false)  // изначально скрыт — в DOM нет вообще
dom.printDOM()

dom.vIf(panel, true)   // пользователь вошёл как админ
dom.printDOM()

dom.vIf(panel, false)  // вышел из аккаунта
dom.printDOM()

console.log('\n=== v-show: переключаем выпадающее меню ===')
dom.vShow(menu, false) // закрыто, но в DOM присутствует
dom.printDOM()

dom.vShow(menu, true)  // открыто
dom.printDOM()

dom.vShow(menu, false) // снова закрыто — просто display:none
dom.printDOM()

console.log('\n=== Вывод ===')
console.log('v-if: дорогое создание/удаление, идеально для редко меняющихся условий')
console.log('v-show: дешёвое переключение, идеально для частых переключений')

v-if, v-else-if, v-else и v-show

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

Директива v-if полностью добавляет или удаляет элемент из DOM в зависимости от условия. Когда условие ложно, элемент не существует в DOM вообще.

<template>
  <div v-if="isLoggedIn">
    <p>Добро пожаловать, {{ username }}!</p>
    <button @click="logout">Выйти</button>
  </div>
</template>

<script setup>
const isLoggedIn = ref(false)
const username = ref('Алексей')
</script>

Цепочка v-if / v-else-if / v-else

Работает аналогично обычным условным операторам JavaScript:

<template>
  <p v-if="score >= 90">Отлично!</p>
  <p v-else-if="score >= 70">Хорошо</p>
  <p v-else-if="score >= 50">Удовлетворительно</p>
  <p v-else">Нужно подтянуть знания</p>
</template>

Важно: v-else-if и v-else должны идти сразу после элемента с v-if — без других элементов между ними.

v-if на элементе template

Если нужно условно скрыть группу элементов без обёртки в лишний <div>, используется тег <template> — он не рендерится в DOM:

<template v-if="isAdmin">
  <h2>Панель администратора</h2>
  <p>Здесь управление пользователями</p>
  <AdminTable />
</template>

v-show: скрытие через CSS

Директива v-show работает иначе: элемент всегда находится в DOM, но при ложном условии к нему применяется display: none:

<template>
  <div v-show="isVisible">
    Этот блок скрыт через display: none
  </div>
</template>

<script setup>
const isVisible = ref(true)
</script>

Сравнение v-if и v-show

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

Когда использовать v-show: когда элемент часто переключается (например, выпадающее меню, модальное окно которое открывают/закрывают много раз).

Когда использовать v-if: когда условие редко меняется, или при false рендеринг элемента не нужен вообще (например, панель администратора, которую видит лишь малый процент пользователей).

Важная деталь: v-if ленив

Если v-if изначально равно false, Vue вообще не рендерит элемент — не создаёт компонент, не запускает его хуки жизненного цикла. Это важно при работе с тяжёлыми компонентами:

<!-- HeavyChart создастся только когда showChart = true -->
<HeavyChart v-if="showChart" :data="chartData" />

С v-show компонент создастся при первом рендере страницы, даже если он скрыт.

Примеры

Эмуляция v-if и v-show: разница между удалением из DOM и скрытием через display:none

// Сравниваем поведение v-if (удаление из DOM) и v-show (display: none)

// Псевдо-DOM для демонстрации
class PseudoDOM {
  constructor() {
    this.elements = new Map()
    this.parent = { children: [] }
  }

  createElement(tag, id) {
    const el = { tag, id, style: {}, inDOM: false }
    this.elements.set(id, el)
    return el
  }

  // v-if: добавляем/удаляем элемент из DOM
  vIf(el, condition) {
    if (condition && !el.inDOM) {
      this.parent.children.push(el)
      el.inDOM = true
      console.log(`[v-if] <${el.tag}#${el.id}> ДОБАВЛЕН в DOM`)
    } else if (!condition && el.inDOM) {
      this.parent.children = this.parent.children.filter(c => c !== el)
      el.inDOM = false
      console.log(`[v-if] <${el.tag}#${el.id}> УДАЛЁН из DOM`)
    } else {
      console.log(`[v-if] <${el.tag}#${el.id}> без изменений (condition=${condition})`)
    }
  }

  // v-show: меняем только display
  vShow(el, condition) {
    if (!el.inDOM) {
      this.parent.children.push(el)
      el.inDOM = true
    }
    el.style.display = condition ? '' : 'none'
    console.log(`[v-show] <${el.tag}#${el.id}> display="${el.style.display || 'block'}" (в DOM: да)`)
  }

  printDOM() {
    console.log('\nТекущее состояние DOM:')
    if (this.parent.children.length === 0) {
      console.log('  (пусто)')
    }
    this.parent.children.forEach(el => {
      const display = el.style.display === 'none' ? ' [скрыт: display:none]' : ''
      console.log(`  <${el.tag} id="${el.id}"${display}>`)
    })
  }
}

const dom = new PseudoDOM()
const panel = dom.createElement('div', 'admin-panel')
const menu = dom.createElement('nav', 'dropdown-menu')

console.log('=== v-if: переключаем панель администратора ===')
dom.vIf(panel, false)  // изначально скрыт — в DOM нет вообще
dom.printDOM()

dom.vIf(panel, true)   // пользователь вошёл как админ
dom.printDOM()

dom.vIf(panel, false)  // вышел из аккаунта
dom.printDOM()

console.log('\n=== v-show: переключаем выпадающее меню ===')
dom.vShow(menu, false) // закрыто, но в DOM присутствует
dom.printDOM()

dom.vShow(menu, true)  // открыто
dom.printDOM()

dom.vShow(menu, false) // снова закрыто — просто display:none
dom.printDOM()

console.log('\n=== Вывод ===')
console.log('v-if: дорогое создание/удаление, идеально для редко меняющихся условий')
console.log('v-show: дешёвое переключение, идеально для частых переключений')

Задание

Создай Vue-приложение с панелью управления. Добавь блок с балансом счёта, который управляется через v-if (полностью удаляется из DOM, если showBalance равно false). Добавь блок уведомлений через v-show (скрывается через display: none). Добавь цепочку v-if / v-else-if / v-else для отображения статуса: если score >= 90 — "Отлично", если >= 70 — "Хорошо", иначе — "Нужно подтянуть". Все переключатели управляются через v-model на чекбоксах.

Подсказка

showBalance и showNotification — ref(true). score — ref(75). v-if="showBalance", v-show="showNotification". Для оценки: v-if="score >= 90", v-else-if="score >= 70". v-model.number на range возвращает число.

Загружаем среду выполнения...
Загружаем AI-помощника...