События
Прежде чем приступить к прочтению данной главы, стоит определиться, что же из себя представляют события web-страницы. Так вот – события – это любые действия пользователя, будь то ввод данных с клавиатуры, проматывание страницы или передвижения мышки, и конечно же "клики".
А ещё существуют события создаваемые скриптами, и их обработчики – триггеры и хэндлеры, но о них чуть позже.
jQuery работает практически со всеми событиями в JavaScript'е, приведу список оных с небольшими пояснениями:
change — изменение значения элемента (значение, при потери фокуса, элемента отличается от изначального, при получении фокуса)
click — клик по элементу (порядок событий: "mousedown", "mouseup", "click")
dblclick — двойной щелчок мышки
resize — изменение размеров элементов
scroll — скроллинг элемента
select — выбор текста (только для "input[type=text]" и "textarea")
submit — отправка формы
focus — фокус на элементе - актуально для "input[type=text]", но в современных браузерах работает и с другими элементами
blur — фокус ушёл с элемента — актуально для "input[type=text]" — срабатывает при клике по другому элементу на странице или по событию клавиатуры (к примеру переключение по tab'у)
focusin — фокус на элементе, данное событие срабатывает на предке элемента, для которого произошло событие "focus"
focusout — фокус ушёл с элемента, данное событие срабатывает на предке элемента, для которого произошло событие "blur"
keydown — нажатие клавиши на клавиатуре
keypress — нажатие клавиши на клавиатуре (keydown → keypress → keyup)
keyup — отжатие клавиши на клавиатуре
load — загрузка элемента (например <img>)
unload — выгрузка элемента (например "window")
mousedown — нажатие клавиши мыши
mouseup — отжатие клавиши мыши
mousemove — движение курсора
mouseenter — наведение курсора на элемент, не срабатывает при переходе фокуса на дочерние элементы
mouseleave — вывод курсора из элемента, не срабатывает при переходе фокуса на дочерние элементы
mouseover — наведение курсора на элемент
mouseout — вывод курсора из элемента
Опробовать события можно на примере с событиями мышки и элементами формы. Для большинства событий существуют "shorthand" методы, так для отслеживания "click" можно использовать "click()" :)
Вызов большинства из перечисленных событий можно эмулировать непосредственно из самого скрипта:
<script> $("#menu li a").click() // или используя метод trigger $("#menu li a").trigger("click") </script>
Теперь стоит рассказать немного и об обработчиках событий, для примера возьму код строкой выше, и слегка его модифицирую:
$("#menu li a").click(function(event){ alert("Hello!") })
Теперь кликнув по ссылке вы увидите приветствие и после закрытия оного браузер перейдет по ссылке указанной в атрибуте "href". Но это не совсем то, что мне хотелось – надо было лишь вывести текст, и никуда не уходить. Ага, для этого стоит отменить действие по умолчанию:
$("#menu li a").click(function(event){ alert("Hello!"); event.preventDefault(); })
Теперь перехода нет, т.к. метод "preventDefault()" предотвращает данное действие. Но вот если кто-то повесит обработчик на само меню?
$("#menu").click(function(event){ alert("Menu!"); })
В результате мы получим два сообщения, но почему? Если у вас возникает подобный вопрос, значит вы еще не знакомы с тем, как обрабатываются события. Попробую кратенько дать вводную, когда вы кликаете на элементе в DOM дереве, то происходит "погружение" события – т.е. вначале все родительские элементы могут обработать "клик", и лишь потом он доберётся до элемента по которому был совершён, но и это еще не всё, затем событие начинает проделывать обратный путь – "всплывает", давая тем самым второй шанс родительским элементам обработать событие.
Но не так всё гладко, у нас же есть IE, который принципиально не работает с "погружением", поэтому все решили идти по пути наименьшего сопротивления и обрабатывают события лишь на этапе "всплытия".
Рекомендую к прочтению "Порядок срабатывание событий" из учебника Ильи Кантора
Хорошо, вроде бы понятно, теперь вернёмся к нашему примеру, и пытаемся понять что же у нас происходит – у нас есть обработчик клика для ссылки и непосредственно для самого меню, в котором эта ссылка находится. Теперь кликая по ссылке, срабатывает обработчик события на ссылке, и затем событие всплывает до меню, и срабатывает его обработчик события "click". Но это не совсем желаемый результат, и для борьбы с подобным вредительством, необходимо останавливать "всплытие" событий:
$("#menu li a").click(function(event){ alert("Hello!"); event.preventDefault(); event.stopPropagation(); })
Для ускорения разработки в jQuery есть быстрый способ вызова этих двух методов за раз:
$("#menu li a").click(function(event){ return false; // вот это он :) })
Теперь у вас есть достаточный багаж знаний, чтобы легко манипулировать событиями на странице. Хотя я добавлю еще немного — для того, чтобы сработал лишь ваш обработчик события, можно использовать метод "stopImmediatePropagation()":
$("#menu li a").click(function(event){ alert("Hello!"); event.stopImmediatePropagation(); return false; }) $("#menu li a").click(function(event){ alert("Hello again!"); return false; })
В данном примере, при клике по ссылке будет выведено лишь одно сообщение. И да, порядок имеет значение.
Учимся рулить
Мы уже успели познакомиться с методом "click()", в действительности этот метод представляет из себя обёртку для вызова "on()" и "trigger()":
if (arguments.length > 0) { this.on("click", null, data, fn ) : } else { this.trigger("click"); }
Ой, код я чуть-чуть изменил — для читаемости, если же любопытство восторжествует, то ищите в исходном коде по строке "dblclick"
Ну так давайте же попробуем без этих обёрток:
// вешаем обработчик $('.class').on('click', function(){ // что-то делаем }); // вызываем обработчик $('.class').trigger('click'); // отключаем обработчик $('.class').unbind('click');
Можно повесить обработчик событий практически на любой объект:
// проще некуда var obj = { test:function() { console.log('obj.test'); } } // создаём обработчик произвольного события someEvent $(obj).on('someEvent', function(){ console.log('obj.someEvent'); this.test(); }); // инициируем событие someEvent $(obj).trigger('someEvent'); // полюбопытствуем console.log(obj);
Скопируйте приведенный код в консоль и запустите, я думаю вам будет интересно ;)
Пространство имен
Как вы уже узнали, когда мы хотим создать/удалить свой обработчик событий, мы пишем следующий код:
// создаем свой обработчик $('.class').on('click', function(){ // что-то делаем }); // удаляем все обработчики $('.class').unbind();
Но как всегда, есть ситуации когда нам необходимо отключить не все обработчики (как пример, надо отключить обработку какого-то контрола определенным плагином), в этом случае нам на помощь приходят пространства имен, использовать их достаточно легко:
// создаём обработчик $('.class').on('click.namespace', function(){ // что-то делаем }); // вызываем обработчик $('.class').trigger('click.namespace'); // вызываем все обработчики без пространства имён $('.class').trigger('click!'); // удаляем все обработчики click в данном пространстве имён $('.class').unbind('click.namespace');
Еще примерчик, вешаем обработчик, который выводит текст в консоль:
$('.class').on('click.namespace', function(){ console.log('bang'); }); // вызываем событие, наш обработчик сработает $('.class').trigger('click.namespace'); // тоже работает $('.class').trigger('click'); // событие из другого пространства имён, наш обработчик не будет вызван $('.class').trigger('click.other');
Также, есть поддержка нескольких пространств имён:
$('.class').on('click.a.b', function(){ // для пространства имён a и b }); // вызываем обработчик из пространства a $('.class').trigger('click.a'); // отменяем обработчик click для пространства b $('.class').unbind('click.b');
Можно одним махом удалить все обработчики с определенного пространства имен:
// обработчик клика $('.class').on('click.namespace', function(){}); // обработчик фокус $('.class').on('blur.namespace', function(){}); // передумали, и все отменили $('.class').unbind('.namespace');
Официальная документация скудна на этот счёт, и я надеюсь мой пример поможет лучше разобраться в данном вопросе.
<!DOCTYPE html> <html dir="ltr" lang="en-US"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>События и пространства имён</title> <link rel="profile" href="http://gmpg.org/xfn/11"/> <link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/> <link rel="stylesheet" href="css/styles.css"/> <script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript" src="js/code.js"></script> <script type="text/javascript"> $(function(){ $('#myButton').click(function(event){ return false; }); }); </script> <style> article ul { margin: 20px; float:left; list-style: none } article a { display: block; padding: 4px 8px; border:1px solid #456; border-radius: 2px; -moz-border-radius: 2px; -webkit-border-radius: 2px; } </style> </head> <body> <div id="content" class="wrapper box"> <div id="output"> <h3>Output</h3> <pre></pre> </div> <menu label="Try..."> <a href="events.form.html" title="go prev" class="button alignleft" rel="prev">← Prev </a> <a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a> <a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a> <hr/> <pre><code>$(<span>'#myButton'</span>).on(<span>'click'</span>, function(){ appendOut(<span>"click\n"</span>); })</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).on(<span>'click.space'</span>, function(){ appendOut(<span>"click.space\n"</span>); })</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).on(<span>'click.my'</span>, function(){ appendOut(<span>"click.my\n"</span>); })</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).on(<span>'click.my.space'</span>, function(){ appendOut(<span>"click.my.space\n"</span>); })</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).trigger(<span>'click'</span>)</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).trigger(<span>'click!'</span>)</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).trigger(<span>'click.my!'</span>)</code></pre> <button type="button" class="code">Run Code</button> <pre><code>$(<span>'#myButton'</span>).off(<span>'.space'</span>)</code></pre> <button type="button" class="code">Run Code</button> </menu> <header> <h1>Работа с пространством имён</h1> <h2>Это уже круто знать и использовать</h2> </header> <article> <a href="#" id="myButton" class="button">#myButton</a> </article> <footer> ©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a> </footer> <script type="text/javascript"> var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-1669896-2']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script> </div> </body> </html>