Pull to refresh

Пример использования пользовательских событий

Reading time4 min
Views7.6K
Наверное много кто знает что в jQuery есть набор стандартных событий, таких как Click или MouseDown и прочие, на которые можно повесить обработчики или возбудить с помошью функций click() mousedown() и прочих. Чуть поменьше людей знают, что те-же самые действия можно сделать с помощью функций bind() и trigger():
$(document).bind('click', function(){
  alert('It works!');
});

$(document).trigger('click');


* This source code was highlighted with Source Code Highlighter.

И наверное мало кто знает, что в функциях bind() и trigger() можно использовать свои собственные события. Зачем это нужно, я и хочу рассказать на примере.

Постановка проблемы

Представим, что у нас на сайте полно всяких всплывающих окон, причем вызываются они из разных мест, какие-то всплывают с информацией о товаре, какие-то с формой логина, какие-то еще где-то. Первая мысль о том, как это реализовать, наверное, будет такой:
$('#products .item .info').bind('click', function(){
  $(this).parents('.item').eq(0).find('.float').fadeIn(500);
});

$('#login-link').bind('click', function(){
  $('#login-form').fadeIn(500);
});


* This source code was highlighted with Source Code Highlighter.

Мысль эта заведомо неправильная, и вы это поймете, как только дизайнер скажет «мне кажется что лучше бы они появлялись не за 0,5 секунд, а за 2» или «я имел ввиду, что оно должно вылетать слева, а не справа» и вам придется искать и править все места, де у вас появляется это чертово окошко.

Второй вариант, как это реализовать, наверное будет примерно такой:
function ShowMe(el) {
  el.fadeIn(500);
}

$('#products .item .info').bind('click', function(){
  ShowMe($(this).parents('.item').eq(0).find('.float'));
});

$('#login-link').bind('click', function(){
  ShowMe($('#login-form'));
});


* This source code was highlighted with Source Code Highlighter.

Уже лучше, но и тут не без проблем. Дело в том, что сам элемент, который вы выбрали, не несет никакой информации, какой функции его нужно передать, поэтому вам придется помнить самому что куда пихать и постоянно заглядывать в код. К тому-же, я, например, люблю весь код заворачивать в функцию, ограничивая область видимости и если понадобится где-то в контенте поставить всплывающее окно, придется выносить функции вроде ShowMe в глобальную область видимости.

У обоих методов есть дополнительная общая проблема: помимо появления окошка, нужно еще позаботиться о его скрытии, которое, во первых, тоже может быть анимированным, а во вторых, очень часто после закрытия окна нужно сделать какие-то дополнительные действия, которые вам тоже придется как-то учитывать при каждом способе закрытия окна (а способов можно придумать сколько угодно, крестик, кнопка «закрыть», ссылка «закрыть» в тексте окна, нажатие вне окна).

Матерые программисты наверное скажут, что нужно создавать класс и наследовать его для каждого типа всплывающего окошка, переопределяя методы скрытия и показа. Но я бы хотел предложить другой путь как все это структурировать и избежать каши в коде и в голове. Если вы прочитали заголовок и текст до хабраката (а есть такие, кто не прочел?), наверное уже догадались, что именно я хочу предложить.

Используем пользовательские события

Я подготовил небольшой пример, в котором как раз представлены 2 подхода. Код первого, без использования событий, находится в блоке <div id="not-envents">. Второй, соответственно, в <div id="envents">.
Что я хотел показать первым примером:
  1. Смешано то, что называется «логикой» и «представлением», в одном месте определяется что должно происходить и как это должно делаться
  2. Когда понадобилось сделать .another-link1 (который гипотетически находится вообще в другом файле, просто должен открывать то же самое окно), пришлось повторить весь код, отвечающий за показ
  3. Когда понадобилось сделать ссылку в «Window 2», закрывающую окно прямо в тексте, пришлось повторить код, отвечающий за скрытие. Причем это простейший случай, все могло быть намного хуже.
Во втором примере я использую пользовательские события «hidefloat» и «showfloat». Что я хотел показать вторым примером:
  1. Можно выделить какие-то общие элементы для всех всплывающих окон и написать их логику в одном месте, что и показано на примере кнопки .close
  2. «Представление» (та часть, которая говорит как именно должно прятаться окно) полностью отделено от логики. Причем, конечно, название «представление» тут более чем условное. Очень часто может понадобиться при появлении окна показывать какие-то дополнительные элементы, а при скрытии прятать.
  3. Все события, навешанные на элементы (.link1, .link2, .link3) четко говорят, что нужно делать, но ничего не говорят о том, как это нужно делать.
  4. Код ссылки в тексте в «Window 2» также говорит только то, что окно должно быть спрятано. Если то, каким образом оно должно прятаться, изменится, нам не придется править ссылку в «Window 2».
  5. Наконец, становиться возможным сделать ссылку «.closeall», которая также ничего не знает о том, как будут прятаться окна. Даже на такой простой страничке видно, что создание кнопки «.closeall» для первого варианта — что-то из разряда фантастики.

Естественно, все что я описал, это только пример того, какие проблемы могут решить пользовательские события, на самом деле область их применения не ограничивается одним всплывающим окном.
Tags:
Hubs:
+39
Comments29

Articles