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

Обработка кликов и пользовательских событий в Vue

Автор

Олег Марков

Введение

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

В этой статье я покажу, как реализовать обработку кликов, обрабатывать всевозможные действия пользователя, использовать модификаторы событий, передавать параметры, а также создавать и "прокидывать" собственные события между компонентами. Каждый аспект будет подкреплен объяснениями и примерами кода, чтобы вы могли сразу применять полученные знания на практике.

Основы событий в Vue

Декларативное связывание событий (v-on)

В Vue работа с событиями строится главным образом вокруг директивы v-on. Это специальная конструкция в шаблоне компонента, которая связывает событие DOM с вашим методом. Для наиболее частых событий есть сокращение в виде @.

Пример: Обработка клика

Давайте рассмотрим базовый пример — обработку нажатия на кнопку:

<template>
  <button @click="handleClick">Нажми меня</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      // Вызывается при клике на кнопку
      alert('Кнопка была нажата!');
    }
  }
}
</script>

Смотрите, я использую сокращение @click вместо полного v-on:click. Этот способ более краткий и распространенный.

Как работает v-on

Когда вы пишете @click="handleClick", Vue добавляет слушатель события на этот DOM-элемент при рендеринге компонента и убирает его, когда элемент удаляется. Вам не нужно заботиться о ручной привязке и отписке от событий — это делает за вас фреймворк.

Передача аргументов в обработчик

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

<template>
  <button @click="sayHello('Иван')">Привет</button>
</template>

<script>
export default {
  methods: {
    sayHello(name) {
      alert(`Привет, ${name}!`);
    }
  }
}
</script>

Здесь аргумент 'Иван' передается прямо из шаблона.

Передача самого события

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

<template>
  <button @click="logEvent($event)">Логировать событие</button>
</template>

<script>
export default {
  methods: {
    logEvent(event) {
      // Доступен весь объект событий DOM
      console.log(event);
    }
  }
}
</script>

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

Vue предоставляет ряд модификаторов, которые позволяют изменять стандартное поведение события, не прибегая к дополнительному коду в методах.

Основные модификаторы

  • .stop — вызывает event.stopPropagation(), предотвращая всплытие события выше по дереву компонентов.
  • .prevent — вызывает event.preventDefault(), отменяя стандартное действие элемента (например, отправку формы).
  • .capture — обработка события на этапе перехвата, а не всплытия.
  • .self — обработчик сработает только если событие инициировано именно на этом элементе.
  • .once — обработчик выполнится только один раз.
Пример использования модификаторов
<template>
  <form @submit.prevent="doSubmit">
    <!-- Отправка формы не приведет к перезагрузке страницы -->
    <button type="submit">Отправить</button>
  </form>
</template>

<script>
export default {
  methods: {
    doSubmit() {
      // Ваш код отправки данных
    }
  }
}
</script>

Добавление .prevent экономит необходимость вручную вызывать event.preventDefault().

Комбинирование модификаторов

Вы можете использовать несколько модификаторов сразу:

<button @click.stop.prevent="onClick">Заблокировать</button>

В этом примере и всплытие будет остановлено, и стандартное действие отменено.

Обработка событий с клавиатуры и мыши

Vue поддерживает обработку событий клавиатуры и мыши с помощью дополнительных модификаторов.

Модификаторы клавиш

Vue позволяет настроить обработку только определенной клавиши. Используйте так:

<input @keyup.enter="onEnter" />

Этот обработчик вызовется, только если пользователь нажал Enter в поле ввода.

Список популярных клавиш
  • enter для Enter
  • esc для Escape
  • tab для Tab
  • delete (кнопка Delete и Backspace)
  • space для пробела
  • arrow-up, arrow-down, arrow-left, arrow-right

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

Для обработки, например, только правого клика мышью, используйте .right:

<button @click.right="onRightClick">ПКМ</button>

Обратите внимание, что срабатывает только клик правой кнопкой мыши.

Пользовательские события (Custom Events)

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

Вызов события через $emit

В дочернем компоненте вы можете возбудить пользовательское событие при помощи метода $emit.

Смотрите, я покажу пример:

<!-- ChildComponent.vue -->
<template>
  <button @click="notifyParent">Сообщить родителю</button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      // Провоцируем событие customEvent
      this.$emit('customEvent', 'данные от дочернего');
    }
  }
}
</script>

В родительском компоненте вы ловите это событие:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent @customEvent="parentHandler" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: { ChildComponent },
  methods: {
    parentHandler(payload) {
      alert('Родитель получил: ' + payload);
    }
  }
}
</script>

Передача данных организована тем же образом, что и для обычных событий DOM.

Особенности bubbling и именование событий

В отличие от событий DOM, пользовательские события Vue не всплывают автоматически через несколько уровней компонентов. Если нужен эффект сквозного проброса (bubbling), смотрят в сторону передачи событий вручную через $emit у промежуточных компонентов или используют функции-обратные вызовы (props).

Vue придерживается "kebab-case" для имен событий (my-event). В шаблоне пишите @my-event, а при вызове $emit("my-event").

Обработка событий на уровне родителя

Vue позволяет обрабатывать события не только на дочернем элементе, но и на любом родительском, используя их специфическое поведение. Например, это удобно для реализации делегирования событий.

<template>
  <div @click="parentHandler">
    <button>Кнопка 1</button>
    <button>Кнопка 2</button>
  </div>
</template>

В этом примере любой клик внутри div обработается одним методом. Через event.target можно выяснить, на какой элемент был совершен клик.

Использование модификатора .native

Если дочерний компонент по сути представляет собой элемент DOM, но вы хотите подписаться на его DOM-события из родителя, в Vue 2 предлагается модификатор .native:

<MyButton @click.native="onNativeClick" />

С приходом Vue 3 этот модификатор считается устаревшим. Вместо него рекомендуется пробрасывать события через $emit внутри компонента.

Добавление слушателей событий напрямую через JS

Иногда возникает потребность добавить обработчик событий напрямую к элементу не через шаблон, а через JavaScript — например, при работе с внешними библиотеками. Для этого чаще используют хуки жизненного цикла (mounted, unmounted):

<template>
  <button ref="myBtn">Слушать напрямую</button>
</template>

<script>
export default {
  mounted() {
    // Пример прямого добавления обработчика
    this.$refs.myBtn.addEventListener('click', this.onClick);
  },
  beforeUnmount() {
    // Не забывайте чистить обработчики!
    this.$refs.myBtn.removeEventListener('click', this.onClick);
  },
  methods: {
    onClick() {
      alert('Кнопка поймала клик через addEventListener');
    }
  }
}
</script>

Применение событий в сочетании с v-model

В связке v-model и пользовательских событий стандарт — использование событий input (или update:modelValue для Vue 3). Ваша задача — обеспечить вызов $emit('update:modelValue', новое_значение) при изменении значения внутри дочернего компонента.

<!-- CustomInput.vue -->
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

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

Теперь компонент можно использовать с v-model из родителя, и изменения будут передаваться двусторонне.

Обработка событий на глобальном уровне

Для глобальных событий (например, клик по документу или клавиша на всем окне) используйте хуки жизненного цикла и методы JavaScript:

<script>
export default {
  mounted() {
    // Обработчик глобального события
    window.addEventListener('keydown', this.onKeydown);
  },
  beforeUnmount() {
    window.removeEventListener('keydown', this.onKeydown);
  },
  methods: {
    onKeydown(event) {
      // Глобальное прослушивание всей клавиатуры
      console.log('Была нажата клавиша:', event.key);
    }
  }
}
</script>

Обязательно очищайте такие обработчики, чтобы избежать утечек памяти.

Использование событий с модификаторами mouse и key в одном выражении

Vue поддерживает и комбинирование разных модификаторов:

<button @click.right.prevent="onRight">ПКМ без контекстного меню</button>
<input @keyup.enter.ctrl="saveOnCtrlEnter" />

В первом случае срабатывает только правый клик по кнопке и не открывает контекстное меню. Во втором — действие происходит только по одновременному нажатию Ctrl+Enter.

Вложенные и динамические события

Если у вас список элементов с обработкой кликов, просто используйте цикл v-for:

<template>
  <ul>
    <li v-for="(item, i) in items" :key="i" @click="selectItem(item)">
      {{ item }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: ['Яблоко', 'Банан', 'Груша']
    }
  },
  methods: {
    selectItem(item) {
      alert('Вы выбрали ' + item);
    }
  }
}
</script>

В этом примере у каждого пункта списка свой обработчик, получающий данные элемента.

Заключение

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

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

Как передать несколько параметров из шаблона в обработчик события?

Пишите все параметры, разделяя их запятыми, при этом чтобы получить объект события, передайте специальный аргумент $event:

<button @click="myHandler(param1, param2, $event)">Клик</button>

В вашем методе myHandler первым и вторым параметром будут ваши значения, а третьим — объект события.

Почему не работает модификатор .native на компонентах во Vue 3?

В Vue 3 модификатор .native больше не поддерживается. Для передачи DOM-событий наружу используйте $emit в дочернем компоненте, а обработку производите через слушатель событий в родительском шаблоне без .native.

Как передать кастомное событие через несколько уровней компонентов?

Вам нужно вручную прокидывать событие через промежуточные компоненты с помощью $emit. Каждый компонент должен слушать событие и, получая его, эмитить наружу. Либо используйте для связи provide/inject или глобальные средства (например, mitt, event bus).

Как организовать делегирование событий в списке элементов?

Навесьте обработчик на контейнер (например, ul). В обработчике анализируйте event.target или используйте атрибуты (data-*) для идентификации, какой элемент списка был нажат.

Что делать, если обработка события становится сложной и нужно избавиться от лишнего кода в шаблоне?

Вынесите обработчик в методы, не пишите длинные выражения внутри шаблона, старайтесь логику обрабатывать только в JS, а не в HTML-части. Используйте вычисляемые свойства и методы для сложных сценариев.

Стрелочка влевоСоздание и использование компонентов в Vue JSИспользование классов в Vue для организации кода и компонентовСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний