Skip to content

Работа с формами

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

template
<input
  :value="text"
  @input="event => text = event.target.value"
>

Директива v-model помогает упростить указанное выше до:

template
<input v-model="text">

Кроме того, v-model может быть использована на полях различных типов, элементах <textarea> и <select>. Она автоматически разворачивается на различные пары свойств и событий DOM в зависимости от элемента на котором используется:

  • Элементы <input> с текстовым типом и <textarea> используют свойство value и событие input;
  • Элементы <input type="checkbox"> и <input type="radio"> используют свойство checked и событие change;
  • Элементы <select> используют свойство value и событие change.

Примечание

Директива v-model игнорирует начальное значение атрибутов value, checked или selected на любых элементах форм. Источником истины всегда считается текущее состояние JavaScript. Начальное значение нужно объявить на стороне JavaScript, используя опцию data в компонентеAPI реактивности.

Обычное использование

Текст

template
<p>Сообщение: {{ message }}</p>
<input v-model="message" placeholder="отредактируй меня" />

Сообщение:

Примечание

Для языков, которые требуют IME (китайский, японский, корейский и т.д.), можно заметить, что v-model не обновляется во время IME-композиции. Если необходимо обрабатывать и эти обновления, используйте слушатель события input и привязку к value вместо использования v-model.

Многострочный текст

template
<span>Многострочное сообщение:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="введите несколько строчек"></textarea>
Многострочное сообщение:

Внутри <textarea> ИНТЕРПОЛЯЦИЯ НЕ РАБОТАЕТ, используйте v-model.

template
<!-- НЕ БУДЕТ РАБОТАТЬ -->
<textarea>{{ text }}</textarea>

<!-- А так работает -->
<textarea v-model="text"></textarea>

Чекбоксы

Один чекбокс, привязанный к булевому значению:

template
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

Список чекбоксов, привязанных к массиву или значениям Set:

js
const checkedNames = ref([])
js
export default {
  data() {
    return {
      checkedNames: []
    }
  }
}
template
<div>Отмеченные имена: {{ checkedNames }}</div>

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>

<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>

<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
Отмеченные имена: []

В этом случае массив checkedNames всегда будет содержать значения выбранных чекбоксов.

Радиокнопки

template
<div>Выбрано: {{ picked }}</div>

<input type="radio" id="one" value="Один" v-model="picked" />
<label for="one">Один</label>

<input type="radio" id="two" value="Два" v-model="picked" />
<label for="two">Два</label>
Выбрано:

Выпадающие списки

Выбор одного варианта из списка:

template
<div>Выбрано: {{ selected }}</div>

<select v-model="selected">
  <option disabled value="">Выберите один из вариантов</option>
  <option>А</option>
  <option>Б</option>
  <option>В</option>
</select>
Выбрано:

Примечание

Если начальное значение выражения v-model не соответствует ни одному из вариантов списка, элемент <select> будет отображаться в «невыбранном» состоянии. В iOS это приведёт к тому, что пользователь не сможет выбрать первый элемент, потому что iOS не сгенерирует событие change в этом случае. Поэтому рекомендуется добавлять отключённый disabled-вариант выбора с пустым значением value, как показано в примере выше.

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

template
<div>Выбраны: {{ selected }}</div>

<select v-model="selected" multiple>
  <option>А</option>
  <option>Б</option>
  <option>В</option>
</select>
Выбраны: []

Динамическое отображение списка опций с помощью v-for:

js
const selected = ref('A')

const options = ref([
  { text: 'Один', value: 'A' },
  { text: 'Два', value: 'B' },
  { text: 'Три', value: 'C' }
])
js
export default {
  data() {
    return {
      selected: 'A',
      options: [
        { text: 'Один', value: 'A' },
        { text: 'Два', value: 'B' },
        { text: 'Три', value: 'C' }
      ]
    }
  }
}
template
<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.text }}
  </option>
</select>

<div>Выбрано: {{ selected }}</div>

Привязка значений

Для радиокнопок и выпадающих списков в качестве привязываемых значений v-model обычно будут статические строки (или булевые значения для чекбокса):

template
<!-- `picked` будет строкой "a" при выборе -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` может принимать значение true или false -->
<input type="checkbox" v-model="toggle" />

<!-- `selected` будет строкой "abc" при выборе первого пункта -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>

Но иногда может потребоваться привязать значение к динамическому свойству текущего активного экземпляра. Для этого можно использовать v-bind. Кроме того, использование v-bind позволяет привязать значение поля с нестроковыми значениями.

Чекбокс

template
<input
  type="checkbox"
  v-model="toggle"
  true-value="да"
  false-value="нет" />

Атрибуты true-value и false-value — специальные атрибуты Vue, которые работают только в связке с v-model. Здесь значение свойства toggle будет установлено в 'да', когда чекбокс выбран, и в 'нет' когда сброшен. Также можно привязать их к динамическим значением с помощью v-bind:

template
<input
  type="checkbox"
  v-model="toggle"
  :true-value="dynamicTrueValue"
  :false-value="dynamicFalseValue" />

Совет

Атрибуты true-value и false-value не влияют на атрибут value элемента input, потому что браузеры пропускают невыбранные чекбоксы при отправке форм. Чтобы гарантировать отправку одного из двух значений с формой (например, «да» или «нет») используйте радиокнопки.

Радиокнопки

template
<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />

Значение pick будет установлено в first при выборе первой радиокнопки, и в значение second при выборе второй.

Выпадающие списки

template
<select v-model="selected">
  <!-- инлайновый объект с данными -->
  <option :value="{ number: 123 }">123</option>
</select>

Директива v-model поддерживает привязку и нестроковых значений! В примере выше, когда опция выбрана, значение selected будет объектом { number: 123 }.

Модификаторы

.lazy

По умолчанию v-model синхронизирует поле ввода с данными по событию input (кроме вышеупомянутых исключений для композиции IME). Можно воспользоваться модификатором lazy, чтобы синхронизация происходила по событию change:

template
<!-- синхронизация после события "change" вместо "input" -->
<input v-model.lazy="msg" />

.number

Для автоматического приведения введённого пользователем к числу можно добавить модификатор number:

template
<input v-model.number="age" />

Если значение не получится привести к числу с помощью parseFloat(), то будет возвращено исходное значение. В частности, если поле ввода пустое (например, после того, как пользователь очистил поле ввода), возвращается пустая строка. Это поведение отличается от свойства DOM valueAsNumber.

Модификатор number автоматически применяется к полям type="number".

.trim

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

template
<input v-model.trim="msg" />

Использование v-model с компонентами

Если ещё не знакомы с компонентами Vue, пока просто пропустите эту секцию.

Встроенные в HTML элементы ввода не всегда соответствуют всем потребностям. К счастью, компоненты Vue позволяют создавать собственные аналоги с полностью настраиваемым поведением. Эти элементы могут работать с директивой v-model! Подробнее в разделе использования компонентов вместе с v-model.

Работа с формамиУже загружено