v-model — директива двусторонней привязки данных (two-way binding) во Vue. Она синхронизирует значение формы с переменной в JavaScript: изменения в поле ввода обновляют переменную, и наоборот.
Ключевые аспекты
Двусторонняя привязка — автоматическая синхронизация данных между UI и состоянием
Синтаксический сахар — эквивалент :value + @input для input, :checked + @change для checkbox
Модификаторы — .lazy, .number, .trim изменяют поведение привязки
Работа с формами — input, textarea, select, checkbox, radio
Кастомные компоненты — можно использовать v-model на собственных компонентах
Плюсы
Минимум кода для работы с формами
Автоматическая синхронизация без ручного управления событиями
Встроенные модификаторы для типичных задач
Работает одинаково для разных типов элементов форм
Минусы
Скрывает реальную механику привязки от новичков
Для сложных сценариев может понадобиться ручная привязка
Разное поведение для разных типов input
Частые ошибки на собеседованиях
Не знают, что v-model это синтаксический сахар (:value + @input)
Путают v-model с v-bind (v-bind — односторонняя привязка)
Забывают про модификаторы .lazy, .number, .trim
Не понимают, как v-model работает с checkbox и radio (массивы, булевы значения)
Введение и проблематика
При работе с формами постоянно нужно:
Получать данные из полей ввода
Обновлять UI при изменении данных в коде
Синхронизировать состояние между JavaScript и DOM
Без специальных инструментов это требует ручного добавления обработчиков событий и обновления DOM. Vue решает эту задачу директивой v-model.
v-model — это синтаксический сахар. Для input он эквивалентен комбинации :value="data" и @input="data = $event.target.value".
По умолчанию v-model обновляется при каждом вводе символа. Модификатор .lazy откладывает обновление до потери фокуса:
vue
<template><!-- Обновляется при каждом символе --> <inputv-model="instant" /><!-- Обновляется при потере фокуса или Enter --> <inputv-model.lazy="delayed" /></template><scriptsetup>import { ref } from'vue'constinstant=ref('')constdelayed=ref('')</script>
.number — преобразование в число
vue
<template> <inputv-model.number="age"type="number" /> <p>Тип: {{ typeof age }}</p> <!-- number --></template><scriptsetup>import { ref } from'vue'constage=ref(0)</script>
Не используйте v-model с вычисляемым свойством без сеттера. Это вызовет ошибку при попытке изменить значение.
vue
<scriptsetup>import { ref, computed } from'vue'constfirstName=ref('Иван')constlastName=ref('Иванов')// ❌ Нет сеттера — нельзя использовать с v-modelconstfullName=computed(() =>`${firstName.value}${lastName.value}`)// ✅ С сеттером — можно использовать с v-modelconstfullNameWritable=computed({get: () =>`${firstName.value}${lastName.value}`,set: (value) => {const [first,last] =value.split(' ')firstName.value = firstlastName.value = last }})</script>