| Vue events |
|
| Добавил(а) microsin |
|
Здесь показаны несколько практических способов обработки событий проекта Vue. [Обработка клика на кнопке] Обработка события onclick вызовом встроенной функции в компоненте MyComponent.vue: // MyComponent.vue < script setup> Обработка события click вызовом пользовательской JavaScript функции компонента: // MyComponent.vue < script setup> Вызов стрелочной функции: < script setup> Если параметров у функции нет, то её в @click можно указывать и без скобок: < MyButton @click="myfunc"> < MyButton @click="myFuncArrow"> Конечно, можно через @ указывать обработку и других событий, которые имеют префикс on, см. врезку ниже. Кроме `onclick`, существует множество других событий для кнопок (и элементов в целом), которые можно разделить на несколько категорий. 1. Основные события мыши. Эти события срабатывают при взаимодействии с помощью мыши или подобного устройства (например, тачпада). onmousedown — срабатывает в момент нажатия кнопки мыши на элементе (палец прикоснулся к экрану). Это происходит до onclick. onmouseup — срабатывает в момент отпускания кнопки мыши на элементе (палец оторвался от экрана). onclick = onmousedown + onmouseup в пределах одного элемента. onmouseenter / onmouseover — когда указатель мыши заходит на область элемента. onmouseenter не всплывает(1). onmouseleave / onmouseout — когда указатель мыши покидает область элемента. onmouseleave не всплывает(1). onmousemove — срабатывает при каждом движении мыши над элементом. oncontextmenu — срабатывает при попытке открытия контекстного меню (обычно клик правой кнопкой мыши). Полезно для отмены стандартного меню. ondblclick — двойной клик. Примечание (1): "событие не всплывает" касается такого понятия, как "всплытие событий". Подробнее см. далее врезку "Всплытие событий". 2. События клавиатуры (актуальны, когда кнопка в фокусе). Часто используются для активации кнопки с клавиатуры (Enter, Space). onkeydown — клавиша нажата (срабатывает первой, при удержании — повторно). onkeyup — клавиша отпущена. onkeypress (устаревшее) — срабатывает при нажатии клавиши, которая генерирует символ (например, буква, цифра). Не рекомендуется к использованию, используйте onkeydown/onkeyup. 3. События фокуса. Кнопка может получать фокус с помощью Tab или клика. onfocus — элемент получил фокус (например, на него перешли с помощью Tab). onblur — элемент потерял фокус. onfocusin / onfocusout — аналоги onfocus/onblur, но события всплывают. 4. События форм (если кнопка внутри < form>). onsubmit — событие формы, а не кнопки, но срабатывает при отправке формы, которую можно инициировать кнопкой с `type="submit"`. onreset — аналогично для кнопки сброса формы (`type="reset"`). 5. Универсальные и Touch-события. onpointerdown, onpointerup, onpointermove и др. — современные универсальные события, которые работают для мыши, пера, тач-интерфейсов. ontouchstart, ontouchend, ontouchmove — специфичные для сенсорных экранов события. [Практический пример использования нескольких событий для кнопки] < button id="myBtn" onmousedown="console.log('Кнопку нажали')" onmouseup="console.log('Кнопку отпустили')" onmouseenter="console.log('Мышь на кнопке')" onmouseleave="console.log('Мышь ушла')" onfocus="console.log('Кнопка в фокусе')" onblur="console.log('Кнопка не в фокусе')" onkeydown="(event) => { if(event.code === 'Space') console.log('Нажат пробел на кнопке'); }"> Нажми меня < /button> Важное замечание по использованию: Сейчас рекомендуется использовать не атрибуты HTML (onclick="..."), а метод addEventListener. Это позволяет: - Добавлять несколько обработчиков на одно событие. const button = document.querySelector('#myBtn'); Итог: самые часто используемые для кнопок события, помимо onclick — это onmousedown/onmouseup (для тонкого контроля), `onmouseenter`/onmouseleave (для визуальных эффектов) и события клавиатуры (onkeydown), чтобы сделать кнопку доступной. Это важная деталь в механике событий JavaScript. [Что такое "всплытие событий" (event bubbling)] Всплытие — это процесс, при котором событие, произошедшее на вложенном элементе, поднимается (всплывает) вверх по иерархии DOM к родительским элементам. Пример всплытия: < div id="parent"> < button id="child">Нажми меня< /button> < /div> При клике на кнопку в консоли появится: 1. `Клик на кнопке` (сначала сработал обработчик на самом элементе). Событие как бы "пузырьком" поднимается от цели вверх по дереву DOM. Теперь про onmouseenter и onmouseleave: эти события не всплывают. Событие срабатывает только на том элементе, на который непосредственно навели курсор (или с которого его увели), и не передается родителям. Пример с mouseenter/mouseleave (не всплывают): < div id="parent" style="padding: 20px; background: lightblue;"> Родитель < button id="child" style="margin: 10px;">Кнопка< /button> < /div> Что произойдет: 1. При наведении курсора снаружи прямо на кнопку: → `mouseenter: кнопка` Событие НЕ всплыло к родителю, родитель не получил mouseenter. 2. При уводе курсора с кнопки прямо наружу: → `mouseleave: кнопка` Событие НЕ всплыло к родителю. 3. При наведении курсора снаружи на родительский div (но не на кнопку): → `mouseenter: родитель` А что с onmouseover и onmouseout? Это их аналоги, которые всплывают. Пример с mouseover/mouseout (всплывают): parent.addEventListener('mouseover', () => console.log('mouseover: родитель')); parent.addEventListener('mouseout', () => console.log('mouseout: родитель')); child.addEventListener('mouseover', () => console.log('mouseover: кнопка')); child.addEventListener('mouseout', () => console.log('mouseout: кнопка')); Что произойдет: 1. При наведении курсора снаружи прямо на кнопку: → `mouseover: кнопка` 2. При уводе курсора с кнопки прямо наружу: → `mouseout: кнопка` Почему это важно? Различия на практике следующие. Проблема с mouseover/mouseout: Из-за всплытия могут возникать "ложные срабатывания". Рассмотрим пример: < div id="menu"> < ul> < li>Пункт 1< /li> < li>Пункт 2< /li> < /ul> < /div> Если мышь переходит с menu на li, произойдет: 1. mouseout на menu (ложное срабатывание!). Получается хаотичное переключение состояния. Решение с mouseenter/mouseleave: эти события срабатывают только при фактическом входе/выходе из всего элемента с потомками, игнорируя переходы между родителем и ребенком. menu.addEventListener('mouseenter', () => { console.log('Вошел в меню (точно!)'); }); Когда что использовать? 1. Используйте mouseenter/mouseleave, когда нужно отследить нахождение курсора внутри всей области элемента (например, для выпадающих меню, тултипов, подсветки карточек). 2. Используйте mouseover/mouseout, когда нужно отследить переходы между конкретными вложенными элементами (например, для сложных интерактивных диаграмм или игровых полей). Современный подход: в большинстве случаев mouseenter/mouseleave ведут себя более предсказуемо и являются предпочтительным выбором для обработки "входа/выхода" курсора. [defineEmits: передача событий между компонентами] Наряду с передачей данных компоненту с помощью defineProps [1] есть также возможность передавать события от одного компонента к другому, опционально с какими-то данными. Это делается с помощью defineEmits. На входе defineEmits принимает в качестве параметров массив событий: как стандартных наподобие click, так и пользовательских, например myEvent. Пример использования defineEmits: // MyComponent.vue < script setup> Здесь myemit принимает первым параметром название определенной через defineEmits функции, и может принять после него произвольное количество параметров. В данном примере передается параметр в виде строки "Сгенерировано мое событие". Это событие можно принять в родительском компоненте следующим образом. Предположим, что родительский компонент это App.vue, а дочерний компонент это MyComponent.vue: // App.vue < script setup> В этом примере указано, что компонент App.vue слушает событие my-event от компонента MyComponent, вызывая при этом пользовательскую функцию getEventData, которая получит параметры, переданные через myemit. Обратите внимание, что имя события myEvent было преобразовано в my-event, так это принято для передачи событий от компонента. По этой причине лучше делать определения в defineEmits дочернего компонента консистетными с именами события в родительском компоненте: // MyComponent.vue < script setup> [Альтернативные записи emits и их валидация] В defineEmits можно передать не массив событий (через квадратные скобки), а объект (через фигурные скобки). Это дает дополнительные возможности по проверке событий. // MyComponent.vue В данном примере валидатор не используется (после myEvent: указано null). Родительский компонент App.vue арим этом не поменялся. Функция валидации. Следующий пример расширяет определение myEvent добавлением функции валидации события. // MyComponent.vue В этом примере если переданные данные payload присутствуют, то событие возвратит true. Переданные данные можно также возвратить и вывести в консоль, например: // MyComponent.vue defineEmits это макрос компилятора Vue 3 Composition API (чаще всего используется в однофайловых компонентах < script setup>), который позволяет компоненту объявлять и генерировать пользовательские события. В Vue компоненты могут общаться с родительскими компонентами через события. defineEmits — это способ объявить, какие события может генерировать дочерний компонент. [Синтаксис defineEmits] 1. Runtime объявление (без валидации) < script setup> 2. Type-based объявление (с TypeScript) < script setup lang="ts"> 3. Object синтаксис (с валидацией) < script setup> [Как использовать в родительском компоненте] < !-- ParentComponent.vue --> < template> < ChildComponent @submit="handleSubmit" @cancel="handleCancel" @update="handleUpdate" /> < /template> [Отличия от Vue 2 Options API] Vue 2 (Options API): < script> Vue 3 (Composition API): < script setup> Ключевые особенности: 1. Только в < script setup>: defineEmits работает только внутри < script setup> и не требует импорта. 2. Компиляционный макрос: код компилируется во время сборки и не выполняется в runtime. 3. TypeScript поддержка: позволяет создавать строго типизированные события. 4. Валидация: можно добавлять валидацию для событий. 5. Возвращаемое значение: emit() возвращает true, если событие прошло валидацию, или false, если нет. [Пример реального использования] < !-- ModalDialog.vue --> < template> < div class="modal" v-if="isVisible"> < div class="modal-content"> < slot>< /slot> < button @click="confirm">OK< /button> < button @click="close">Cancel< /button> < /div> < /div> < /template> [Важные моменты] 1. Именование событий: рекомендуется использовать kebab-case для имен событий в шаблонах (@my-event), но в defineEmits можно использовать camelCase. 2. Не используйте с обычным < script>: < script> 3. Глобальная доступность: в < script setup> defineEmits, defineProps, defineExpose доступны глобально без импорта. [Ссылки] 1. Vue defineProps. |