Pull to refresh

Программная генерация событий DOM 2 Events

Reading time 7 min
Views 42K
image

Вступление


Здравствуйте, Хабрачеловеки.

В этой статье я хочу рассказать сообществу о такой полезной штуке, как DOM Events. Все, кто хоть как то связан с Javascript, знают, что в этом языке события и их обработка являются одним из важнейших и часто используемых свойств, но не многие знают, как эти события генерировать программно. Собственно, этому и посвящена статья: в ней рассказано, что это, зачем нужно, и как это использовать. О listener'ах речи идти не будет, хоть эта тема весьма тесто связана с рассматриваемой.



Что это?



DOM Events позволяют событийно-ориентированным языкам программирования, таким, как JavaScript, JScript, ECMAScript, VBScript and Java, регистрировать различные обработчики событий/слушатели событий (event handlers/listeners) на узлы элементов внутри дерева DOM (HTML, XHTML, XUL, SVG).

Это, к примеру, onClick, onBlur, onMouseOver и так далее. События эти запускаются по определённому действию пользователя: нажатие клавиши, клик, движение курсора за границы элемента. Т.е., при физическом воздействии на «органы управления». Мы же будем учиться запускать такие события программно, без использования устройств ввода и манипуляции.

Зачем это нужно?



Применение можно найти самое разное: just for fun, разработка ботов для bbmmorpg, скрипты автоматизации, читерства (скрипт для «Клавогонок»: вставка нужной буквы в строку ввода и запуск события onKeyUp), «вебдванольности», встречал даже мысли о написании некоего подобия юнит-теста. В общем, на сколько фантазии хватит.

Каких то толковых мануалов по этой теме интернетах найти не удалось, поэтому решил свести и увековечить свои находки на хабре.

Однако, стоит помнить следующее:

«Ручной» запуск (генерация) события не создает по умолчанию действие, связанное с этим событием. Например, программная генерирация события focus на элементе не означает, он получит фокус, вручную сгенерированное событие submit не заставит форму отправить данные (следует использовать метод submit формы), сгенерированное событие нажатия клавиши не означает, что символ появится в поле ввода, программное нажание на ссылку не активирует переход по ней, и т. д. Такие ограничения необходимы в целях безопасности и предотвращения сценариев имитации работы пользователя и взаимодействия с браузером.

Как это использовать?



В общем порядке, алгоритм един:
— получить объект узла DOM, на который будет вешаться событие;
— создать объект необходимого модуля событий;
— инициализировать объект события;
— назначить событие на необходимый узел DOM;

Для начала ознакомимся с существующими модулями:
— Events — родительский модуль. Его наследуют все модуля, о чём будет сказано ниже.
— HTMLEvents — включает в себя события элементов DOM.
— UIEvents — события клавиатуры.
— MouseEvents — события мыши.
— MutationEvents — события модификации дерева DOM.

Структура DOM 2 Events


Существует пять модулей DOM 2 events. Их имена отображают суть события:

Events
  • Охватывает все типы событий


HTMLEvents
  • abort
  • blur
  • change
  • error
  • focus
  • load
  • reset
  • resize
  • scroll
  • select
  • submit
  • unload


UIEvents
  • DOMActivate
  • DOMFocusIn
  • DOMFocusOut
  • keydown
  • keypress
  • keyup
  • также косвенно охватывает MouseEvents


MouseEvents
  • click
  • mousedown
  • mousemove
  • mouseout
  • mouseover
  • mouseup


MutationEvents
  • DOMAttrModified
  • DOMNodeInserted
  • DOMNodeRemoved
  • DOMCharacterDataModified
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemovedFromDocument
  • DOMSubtreeModified


Другие события (такие как 'dblClick') не являются частью спецификации, и браузеры не требуют их поддержки. Браузеры, которые поддерживают их, либо выберут соответствующий модуль (например, ' dblClick' очень хорошо подходит для модуля MouseEvents) либо создадут новый модуль. Вы должны знать, в какой модуль браузер определит такое событие.

Реализация примера события — onClick


«Фальшивые» события создаются с использованием метода document.createEvent, который принимает имя соответствующего модуля событий, включающий необходимое событие. Далее следует подготовка события с помощью метода initEvent (название метода отличается для каждого модуля) и, наконец, запуск события на указанном элементе с помощью метода dispatchEvent. Если вы используете более конкретный тип события, а не универсальный (generic), можно предоставить дополнительную информацию о событии при его подготовке. Несколько сумбурно, но пример всё прояснит:

Чтобы создать событие 'click' на элементе, ID которого равен 'element_id', необходимо:


var element = document.getElementById('element_id'); // Получаем объект необходимого элемента
var o = document.createEvent('MouseEvents');  // Создаём объект события, выбран модуль событий мыши
o.initMouseEvent( 'click', true, true, window, 1, 12, 345, 7, 220, false, false, true, false, 0, null ); // Инициализируем объект события
element.dispatchEvent(o);  // Запускаем событие на элементе


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

Примеры инициализации события для всех модулей:


HTMLEvents и generic Events
initEvent( 'type', bubbles, cancelable )

UIEvents
initUIEvent( 'type', bubbles, cancelable, windowObject, detail )

MouseEvents
initMouseEvent( 'type', bubbles, cancelable, windowObject, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget )

MutationEvents
initMutationEvent( 'type', bubbles, cancelable, relatedNode, prevValue, newValue, attrName, attrChange )

Обратите внимание, хотя prevValue, NewValue, и attrName могут принимать значение null, attrChange всегда должен быть определён, даже если событие не DOMAttrModified (значение 1, 2 или 3)

MouseEvents является подклассом UIEvents, в свою очередь, последний является подклассом модуля Events, так что если вы создаете объект MouseEvents, он будет также наследовать initUIEvent и initEvent методы UIEvents и интерфейсов Events. Так что вы можете выбрать метод инициализации события, который необходимо использовать при его подготовке.(nit*Event)

Запуск события с использованием generic-модуля событий (Демонстрация наследования)


Пример ниже демонстрирует запуск события, в котором используется универсальный метод initEvent, и оставляются неопределенными свойства в их значениях по умолчанию (однако, даже при использовании общих initEvent или initUIEvent, вы все равно должны использовать точное имя модуля, а не имя generic-модуля, или он не будет работать в Mozilla/Firefox, Konqueror, Safari):


var element = document.getElementById('element_id');
var o = document.createEvent('MouseEvents');
o.initEvent('click', true, true); // Используется унаследованный метод модуля Events, а не аналогичный модуля MouseEvents, объект которого был создан
element.dispatchEvent(o);


Клавиатурные события


Клавиатурные события немного сложнее, потому что Mozilla / Firefox не реализует стандарт корректно, и не позволит вам создать ключевые события с использованием общих (generic) UIEvents (он может просто зависнуть или «упасть» с критической ошибкой). Вместо этого он предоставляет внутренний модуль «KeyEvents, и метод инициализации „initKeyEvent“. Метод initKeyEvent принимает следующие параметры:'type', bubbles, cancelable, windowObject, ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode. Вы можете использовать конструкцию if(window.KeyEvent) для обнаружения поддержки модуля KeyEvents в браузере. Браузеры, которые используют UIEvents, не имеют специфической функции инициализации для ключевых событий, поэтому некоторые свойства должны быть добавлены вручную:


var element = document.getElementById('element_id');

if( window.KeyEvent ) // Для FF
 {
  var o = document.createEvent('KeyEvents');
  o.initKeyEvent( 'keyup', true, true, window, false, false, false, false, 13, 0 );
} 
else // Для остальных браузеров
 {
  var o = document.createEvent('UIEvents');
  o.initUIEvent( 'keyup', true, true, window, 1 );
  o.keyCode = 13; // Указываем дополнительный параметр, так как initUIEvent его не принимает
}

element.dispatchEvent(evObj);


События в Internet Explorer


Инициализация событий в Internet Explorer существенно отличается от остальных браузеров. IE имеет метод для ручного запуска события, который называется fireEvent, и доступен с IE 5.5 +. В своей простейшей форме, это похоже на версию DOM, но пузырьки (bubbles) и отменяемые свойства (cancelable properties) недоступны. Метод fireEvent ожидает передачи одного или двух параметров. Первым должно быть название события (например, 'OnChange'), и необязательный второй параметр должен быть объект события, передаваемый обработчику.

Хотя объект window может обнаружить несколько событий в IE (например, load, unload, scroll, resize — все это должно, в соответствии со спецификацией, быть обнаружено объектом document, а не window), это не значит, что fireEvent возможно использовать с объектом window.


var element = document.getElementById('element_id');

if(document.createEvent) // Для реализации кроссбраузерности
 {
  var o = document.createEvent('MouseEvents');
  o.initEvent('click', true, false );
  element.dispatchEvent(o);
} 
else if( document.createEventObject ) // Для IE
 {
   o.fireEvent('click');
}


Если вы хотите указать дополнительную информацию о событии, необходимо использовать метод createEventObject для репликации CreateEvent и init*Event методов DOM. Метод createEventObject обычно возвращает пустой объект события, и вам нужно будет определить параметры самостоятельно.



var element = document.getElementById('element_id');

if(document.createEvent)  // Пример реализации в нормальных браузерах
{
  var o = document.createEvent('MouseEvents');
  o.initMouseEvent( 'click', true, true, window, 1, 12, 345, 7, 220, false, false, true, false, 0, null );
  element.dispatchEvent(evObj);
}

else if(document.createEventObject) // Реализация события в IE
{
  var o = document.createEventObject();
  o.detail = 0;
  o.screenX = 12;
  o.screenY = 345;
  o.clientX = 7;
  o.clientY = 220;
  o.ctrlKey = false;
  o.altKey = false;
  o.shiftKey = true;
  o.metaKey = false;
  o.button = 0;
  o.relatedTarget = null;
  element.fireEvent('click', o);
}


Заключение


Я весьма кратко осветил тему, однако, этого достаточно для понимания её сути. Генерация событий позволяет сделать „за ширмой“ много интересных вещей, а учитывая количество доступных событий, эта тема становится ещё интересней.

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

Удачных Вам жизненных событий без рандомной их генерации :)

Что почитать?


Статья, которая послужила основой этого топика
Описание структуры модулей событий: таблицы, сравнения.
О событиях на Mozilla MDN
Tags:
Hubs:
+69
Comments 26
Comments Comments 26

Articles