Опубликован: 28.02.2016 | Уровень: для всех | Доступ: платный
Лекция 4:

События

< Лекция 3 || Лекция 4: 12 || Лекция 5 >

Прежде чем приступить к прочтению данной главы, стоит определиться, что же из себя представляют события 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>
< Лекция 3 || Лекция 4: 12 || Лекция 5 >
Наталья Маркова
Наталья Маркова
Ярослав Гаевой
Ярослав Гаевой

10 марта 2016 c 20:13 до 22:39 я сдавал экзамен. Однако, за два месяца статус не изменился: "Задание не проверено"

Когда ожидать проверки?

Руслан Жанбосынов
Руслан Жанбосынов
Россия
Дмитрий Молокоедов
Дмитрий Молокоедов
Россия, Новосибирск, НГПУ, 2009