логотип PurpleSchool
логотип PurpleSchool

Обработка пользовательского ввода в Vue.js

Автор

Олег Марков

Введение

Работа с пользовательским вводом — одна из центральных задач в разработке современных реактивных интерфейсов. Во Vue.js эта задача решается очень элегантно благодаря реактивности данных и мощным возможностям по работе с событиями. Через правильное связывание данных и грамотное управление событиями ввода вы получаете контроль над поведением форм, удобство реакций на любые действия пользователей и возможность строить по-настоящему живые приложения.

В этом материале я подробно объясню основные подходы к обработке пользовательского ввода в Vue.js. Покажу стандартные (и неочевидные) способы связывания данных с HTML-формами, дам примеры, объясню детали применения модификаторов событий и рассмотрю, как осуществляется полноценная валидация и контроль за состоянием ввода. В результате разбора вы легко сможете строить любые формы — от текстовых полей до групп радиокнопок и чекбоксов, грамотно реагировать на каждое действие пользователя и обрабатывать полученные данные.


Связывание данных с пользовательским вводом

Vue.js строится на идее двусторонней привязки данных (two-way data binding). Всякий раз, когда пользователь изменяет значение в поле, это мгновенно отражается на связанном свойстве во Vue-компоненте, и наоборот.

Давайте начнем с базового способа — директивы v-model.

Использование v-model для основных типов данных

v-model служит для связи состояний компонента с элементами ввода. Вот простой пример для текстового поля:

<template>
  <input v-model="message" placeholder="Введите сообщение">
  <p>{{ message }}</p>
</template>

<script>
export default {
  data() {
    return {
      message: ''
    }
  }
}
</script>

// В этом примере переменная message обновляется каждый раз, когда пользователь что-то вводит в поле

Работа с различными элементами

v-model работает не только с input. Смотрите, как можно привязать данные к checkbox, radio, select:

<!-- Привязка к чекбоксу -->
<input type="checkbox" v-model="checked">
<span>Состояние чекбокса: {{ checked }}</span>
data() {
  return { checked: false }
}

// Если пользователь поставит галочку, checked станет true

<!-- Радиокнопки -->
<input type="radio" value="A" v-model="picked">
<input type="radio" value="B" v-model="picked">
<span>Ваш выбор: {{ picked }}</span>
data() {
  return { picked: '' }
}

// picked примет значение A или B — в зависимости от выбора пользователя

<!-- Селект -->
<select v-model="selected">
  <option value="one">Один</option>
  <option value="two">Два</option>
</select>
<p>Вы выбрали: {{ selected }}</p>
data() {
  return { selected: '' }
}

// selected будет равен one или two

Отслеживание нескольких чекбоксов

v-model поддерживает даже массивы для случая, когда пользователь может выбрать несколько значений:

<input type="checkbox" value="apple" v-model="fruits"> Яблоко
<input type="checkbox" value="orange" v-model="fruits"> Апельсин

<p>Выбранные фрукты: {{ fruits }}</p>
data() {
  return { fruits: [] }
}

// Если пользователь выберет оба чекбокса, fruits будет ["apple", "orange"]

Как работает v-model под капотом

Когда вы используете v-model, Vue синтетически связывает значение поля и данные в компоненте. Для <input type="text"> это означает автоматическое слушание события input и установку атрибута value. Для чекбокса — слушается change и устанавливается checked, а у select — свойство selected.

Давайте посмотрим подробнее:

  • для текстового поля:
    • связывается значение поля (value) с переменной
    • при каждом input значение переменной обновляется
  • для чекбокса:
    • связь идет между свойством checked и переменной true/false

Работа с событиями: методы, слушатели и модификаторы

Иногда нам нужно более тонко контролировать ввод — например, реагировать на нажатие Enter, ловить blur (потеря фокуса) или отправку формы. Для этого во Vue служат директивы событий: v-on (или сокращенно @).

Простой обработчик ввода

Рассмотрим типичный пример:

<input @input="onInput">
methods: {
  onInput(event) {
    // Событие содержит новое значение поля
    this.message = event.target.value
  }
}

// Здесь мы вручную извлекаем значение из события

Частые события и их применение

  • @input: любое изменение содержимого (реагирует мгновенно)
  • @change: событие срабатывает, когда пользователь покинул поле или подтвердил выбор
  • @keyup, @keydown, @keypress: события нажатия клавиш (подойдут, например, чтобы ловить нажатие Enter)
  • @blur, @focus: потеря и получение фокуса полем

Пример обработчика нажатия Enter:

<input @keyup.enter="submit">
methods: {
  submit(event) {
    // Выполняем действие при нажатии Enter
  }
}

Модификаторы событий

Vue предоставляет ряд модификаторов, которые упрощают написание обработчиков.

.lazy

По умолчанию v-model обновляет значение на каждое событие input. С модификатором .lazy обновление произойдёт только на событие change:

<input v-model.lazy="msg">

// Данные обновляются только если поле покинуто или отправлено, а не при каждом вводе символа

.number

Если пользовательское значение — число (например, в поле ввода возраста), .number автоматически приводит введённую строку к числу:

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

// Если пользователь вводит 42, переменная age станет числом 42, а не строкой "42"

.trim

Убирает лишние пробелы в начале и конце:

<input v-model.trim="query">

// Допустимо для очистки ввода перед поиском/отправкой формы

Модификаторы для событий

При работе с событиями можно добавлять такие модификаторы:

  • .prevent — вызывает preventDefault, чтобы отменить стандартное поведение (например, отправку формы)
  • .stop — вызывает stopPropagation, чтобы прекратить дальнейшее всплытие события

Пример:

<form @submit.prevent="onSubmit">
  <input v-model="name">
  <button type="submit">Отправить</button>
</form>

// Здесь форма не обновляет страницу при отправке, а вызывает метод onSubmit


Управление состоянием форм: валидация, ограничение ввода и обратная связь

В большинстве приложений простого сбора значений недостаточно. Важно показывать пользователю ошибки, подсказывать, когда ввод допустим, и мешать отправке некорректных форм.

Ручная валидация полей

Простейшая валидация — проверка в методах:

<input v-model="email" @blur="validateEmail">
<span v-if="emailError">{{ emailError }}</span>
data() {
  return {
    email: '',
    emailError: ''
  }
},
methods: {
  validateEmail() {
    // Простая проверка на @
    if (!this.email.includes('@')) {
      this.emailError = "В адресе должен быть символ @"
    } else {
      this.emailError = ''
    }
  }
}

// После ухода из поля будет показана ошибка, если email некорректный

Ограничение ввода: динамические атрибуты и computed

Можно ограничивать длину, допустимые символы или диапазон чисел:

<input v-model="age" :min="18" :max="99" type="number">

// Vue подставляет значения min/max из переменных

Вы сами решаете, когда разрешать отправку:

<button :disabled="!canSubmit">Отправить</button>
computed: {
  canSubmit() {
    return this.email && !this.emailError
  }
}

// Кнопка становится неактивной, если поле не заполнено или есть ошибка

Управление группами полей: объект форм

Обычно удобнее связывать несколько полей с объектом:

<input v-model="form.username">
<input v-model="form.password">
data() {
  return {
    form: {
      username: '',
      password: ''
    }
  }
}

// Это облегчает отправку всей формы другим компонентам или на сервер

Реактивность при работе с вложенными объектами

Vue отслеживает изменения внутри объекта form, если свойства были объявлены изначально. Однако добавление новых свойств (необъявленных в data) не будет реактивно в старых версиях Vue (до 3.x):

// Не советую так делать:
this.form.newField = 'value' // новое поле не будет реактивным в Vue 2

Лучше сразу определить все нужные поля в data.

Массовая очистка и сброс форм

Сбросить форму до исходного состояния просто:

methods: {
  resetForm() {
    this.form.username = ''
    this.form.password = ''
    // Можно убрать ошибки и доп.состояния
  }
}

// Также можно клонировать "начальный объект" в начале и возвращаться к нему по необходимости


Продвинутые возможности обработки пользовательского ввода

Vue предоставляет вам и более тонкие инструменты работы с пользовательским вводом — кастомные компоненты с поддержкой v-model, дебаунсинг (отложенное реагирование), синхронизацию с Vuex и пр.

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

Можно создавать свои компоненты, которые будут поддерживать v-model:

// Компонент MyInput.vue
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
</template>

<script>
export default {
  props: ['modelValue']
}
</script>

// Теперь этим компонентом можно пользоваться //

Дебаунсинг ввода

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

methods: {
  onInput: _.debounce(function (e) {
    this.query = e.target.value
    this.performSearch()
  }, 500)
}

// Здесь _.debounce — функция lodash, задерживает выполнение поиска до паузы в 500мс после последнего ввода

Работа с нативной формой

Vue позволяет не только связывать значения формы с переменными, но и использовать HTML5-валидацию:

<form @submit.prevent="send">
  <input v-model="email" type="email" required>
  <button>Отправить</button>
</form>

// Здесь браузер сам подскажет пользователю, если email некорректный

Слежение за изменениями с помощью watch

Иногда полезно выполнять действия, когда значение изменилось:

watch: {
  'form.username'(newValue, oldValue) {
    // Например, предзаполнять другое поле или валидировать
  }
}

Работа с различными типами ввода

Флажки и переключатели

  • С одним чекбоксом v-model связывает его с boolean
  • Для группы чекбоксов — с массивом

Часто приходится кастомизировать значения, чтобы, например, получать не только true/false, но и определённые данные:

<input type="checkbox" v-model="flag" true-value="Да" false-value="Нет">
data() { return { flag: '' } }

// flag станет "Да" или "Нет"

Работа с select с несколькими значениями

<select v-model="selectedOptions" multiple>
  <option value="apples">Яблоки</option>
  <option value="oranges">Апельсины</option>
</select>
<p>{{ selectedOptions }}</p>
data() { return { selectedOptions: [] } }

// selectedOptions будет массивом выбранных значений

Использование кастомных событий

Иногда для совместимости или интеграции с библиотеками нужно не просто связать значения, а обрабатывать кастомные события:

<input @custom-event="onCustomInput">

// В целом любой DOM-событие или пользовательское событие можно обработать через v-on/@


Особенности работы в Vue 3

Если вы работаете с Vue 3, логика в целом сохраняется, но меняются детали работы с v-model в компонентах: теперь он работает через проп modelValue и событие update:modelValue. Также Vue 3 улучшил реактивность объектов и массивов.

// В дочернем компоненте
props: ['modelValue']

emit('update:modelValue', value)

// Под капотом поддерживается синхронизация значений между родителем и компонентом


Заключение

Вы теперь знаете, как организовать обработку пользовательского ввода во Vue.js: использовать v-model для двусторонней привязки данных, настраивать события через v-on, применять модификаторы для преобразования или задержки ввода, валидировать данные и управлять сложными формами. Эти инструменты позволяют с легкостью реализовывать сложные сценарии взаимодействия пользователя с формами и полями, поддерживать реактивность интерфейса, реагировать на ошибки ввода и улучшать взаимодействие с приложением. Грамотно выстроенная обработка пользовательского ввода улучшает UX и заботится о качестве вашего кода.


Частозадаваемые технические вопросы и решения

Как очистить все поля формы сразу, если их много?

Сделайте отдельный "эталонный" объект со всеми начальным значениями и используйте Object.assign:

const initialForm = { field1: '', field2: '', field3: 0 }
data() {
  return {
    form: { ...initialForm }
  }
},
methods: {
  resetForm() {
    Object.assign(this.form, initialForm)
  }
}

// Так вы сбросите все поля быстро и реактивно

Как сделать автосохранение ввода при каждом изменении поля?

Используйте watch на нужных полях и выполняйте сохранение в хранилище или на сервер:

watch: {
  'form.fieldName': function(newVal) {
    localStorage.setItem('myField', newVal)
  }
}

// Аналогично можно вызывать сохранение через API

Как валидацию сделать только после первого ввода, а не сразу?

Добавьте флаг wasTouched для каждого поля и показывайте ошибку только после его фокуса или потери фокуса:

data() { return { email: '', emailTouched: false, emailError: '' } }
methods: {
  onBlur() { this.emailTouched = true; this.validateEmail() }
}
// В шаблоне: <input v-model="email" @blur="onBlur">
// При ошибке: <span v-if="emailError && emailTouched">{{ emailError }}</span>

Почему v-model не работает с input type="file"?

v-model не поддерживается на file input, потому что работа с файлами требует прямого доступа к файловым объектам. Используйте @change и вручную сохраняйте выбранные файлы:

<input type="file" @change="onFileChange">
methods: {
  onFileChange(e) {
    this.file = e.target.files[0]
  }
}

Как при вводе запрещать определённые символы (например, только цифры)?

Добавьте фильтрацию или отмену ввода в событии @input/@keydown:

<input @input="onInput" />
methods: {
  onInput(e) {
    // Удаляем все символы кроме цифр
    e.target.value = e.target.value.replace(/\D/g, '')
    this.number = e.target.value
  }
}
Стрелочка влевоИспользование метода map в Vue для обработки массивовОрганизация файлов и структура проекта Vue.jsСтрелочка вправо

Все гайды по Vue

Работа с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueОбзор популярных шаблонов и стартовых проектов на VueКак организовать страницы и маршруты в проекте на VueСоздание серверных приложений на Vue с помощью Nuxt jsРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияНастройка и сборка проектов Vue с использованием современных инструментов
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование метода map в Vue для обработки массивовОбработка пользовательского ввода в Vue.jsОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitИспользование директив и их особенности на Vue с помощью defineСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в Vue
Открыть базу знаний