Браузерные DOM-события в контексте A-Frame

A-Frame — это фреймворк для создания WebVR и WebXR приложений на основе HTML-подобного синтаксиса и трёхмерной сцены, где каждый объект представлен элементом <a-entity> или специализированными компонентами. Управление поведением этих объектов тесно связано с обработкой событий, как специфичных для A-Frame, так и стандартных DOM-событий браузера.

Взаимодействие A-Frame и DOM

Все элементы A-Frame являются DOM-узлами, поэтому они наследуют стандартные методы и события браузера: click, mouseenter, mouseleave, keydown, keyup, mousemove и другие. Это позволяет интегрировать VR-сцену с обычным пользовательским интерфейсом и использовать привычные механизмы подписки на события через addEventListener:

const box = document.querySelector('#box');
box.addEventListener('click', function (evt) {
  console.log('Box clicked!', evt);
});

Важная особенность A-Frame заключается в том, что события распространяются по сцене и иерархии компонентов, что позволяет создавать реакцию на действия пользователя на разных уровнях.

События A-Frame

A-Frame расширяет стандартный DOM набором собственных событий, специфичных для VR:

  • loaded — срабатывает, когда сущность полностью загружена, включая модели и текстуры.
  • model-loaded — применяется к <a-entity> с компонентом gltf-model, сигнализируя о завершении загрузки 3D-модели.
  • raycaster-intersected и raycaster-intersected-cleared — генерируются при пересечении объектов курсором или VR-лучом.
  • stateadded / stateremoved — события для отслеживания изменения состояния сущности через систему setAttribute('state', ...).

Пример обработки события пересечения луча:

const box = document.querySelector('#box');
box.addEventListener('raycaster-intersected', () => {
  box.setAttribute('material', 'color', 'red');
});
box.addEventListener('raycaster-intersected-cleared', () => {
  box.setAttribute('material', 'color', 'blue');
});

Интеграция с обычными событиями мыши и клавиатуры

Для VR-проекта важно учитывать различие между пользовательским взаимодействием через мышь и через контроллеры. A-Frame автоматически сопоставляет события click, mouseenter и mouseleave с VR-лучами и контроллерами.

Обработка нажатий клавиш:

window.addEventListener('keydown', (event) => {
  if (event.code === 'Space') {
    const sphere = document.querySelector('#sphere');
    sphere.setAttribute('position', {x: 0, y: 2, z: -5});
  }
});

События клавиатуры работают на уровне всего документа, а события мыши и VR-лучей — на уровне конкретных сущностей.

Кастомные события и их использование

A-Frame позволяет создавать кастомные события, что упрощает архитектуру интерактивного приложения. Событие создаётся через dispatchEvent и слушается стандартным addEventListener:

const box = document.querySelector('#box');

// Создание кастомного события
const jumpEvent = new CustomEvent('jump', { detail: { height: 2 } });

// Подписка на событие
box.addEventListener('jump', (evt) => {
  const height = evt.detail.height;
  box.setAttribute('position', { x: 0, y: height, z: 0 });
});

// Вызов события
box.dispatchEvent(jumpEvent);

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

Особенности событий в A-Frame

  1. События компонентов: каждый компонент может генерировать события, которые слушаются на уровне сущности. Например, animationcomplete сигнализирует о завершении анимации.
  2. События состояния: система setAttribute('state', ...) позволяет менять состояния сущностей и реагировать на их добавление или удаление через stateadded / stateremoved.
  3. Propagation и bubbling: события могут всплывать по DOM-иерархии сцены, что позволяет слушать их на <a-scene> и обрабатывать все сущности одновременно.
  4. События загрузки: критично для моделей и текстур. loaded и model-loaded помогают избежать работы с объектами до того, как они готовы в сцене.

Примеры интеграции событий в интерактивной сцене

Комбинирование стандартных и A-Frame событий позволяет реализовать полноценный интерактивный опыт:

const box = document.querySelector('#box');

// Изменение цвета при наведении VR-луча
box.addEventListener('mouseenter', () => box.setAttribute('material', 'color', 'green'));
box.addEventListener('mouseleave', () => box.setAttribute('material', 'color', 'yellow'));

// Перемещение при клике
box.addEventListener('click', () => {
  box.object3D.position.y += 1;
});

Эта гибкость позволяет использовать A-Frame не только для визуализации, но и для создания интерактивных приложений с богатым UX, где события мыши, клавиатуры и VR-контроллеров гармонично сочетаются.

Практические советы

  • Всегда проверять событие loaded перед изменением свойств модели.
  • Использовать кастомные события для передачи данных между компонентами вместо глобальных переменных.
  • Для сложных сцен рекомендовано слушать события на уровне <a-scene> и фильтровать по event.target, чтобы не создавать тысячи отдельных слушателей.
  • Сочетание VR-лучей и стандартных DOM-событий позволяет создавать гибкие системы управления, совместимые как с VR, так и с обычным браузером.

Системная работа с DOM-событиями в A-Frame обеспечивает масштабируемость и интерактивность VR-проектов, облегчает управление состояниями объектов и интеграцию с внешними пользовательскими интерфейсами.