Наверное много кто знает что в jQuery есть набор стандартных событий, таких как Click или MouseDown и прочие, на которые можно повесить обработчики или возбудить с помошью функций click() mousedown() и прочих. Чуть поменьше людей знают, что те-же самые действия можно сделать с помощью функций bind() и trigger():
И наверное мало кто знает, что в функциях bind() и trigger() можно использовать свои собственные события. Зачем это нужно, я и хочу рассказать на примере.
Представим, что у нас на сайте полно всяких всплывающих окон, причем вызываются они из разных мест, какие-то всплывают с информацией о товаре, какие-то с формой логина, какие-то еще где-то. Первая мысль о том, как это реализовать, наверное, будет такой:
Мысль эта заведомо неправильная, и вы это поймете, как только дизайнер скажет «мне кажется что лучше бы они появлялись не за 0,5 секунд, а за 2» или «я имел ввиду, что оно должно вылетать слева, а не справа» и вам придется искать и править все места, де у вас появляется это чертово окошко.
Второй вариант, как это реализовать, наверное будет примерно такой:
Уже лучше, но и тут не без проблем. Дело в том, что сам элемент, который вы выбрали, не несет никакой информации, какой функции его нужно передать, поэтому вам придется помнить самому что куда пихать и постоянно заглядывать в код. К тому-же, я, например, люблю весь код заворачивать в функцию, ограничивая область видимости и если понадобится где-то в контенте поставить всплывающее окно, придется выносить функции вроде ShowMe в глобальную область видимости.
У обоих методов есть дополнительная общая проблема: помимо появления окошка, нужно еще позаботиться о его скрытии, которое, во первых, тоже может быть анимированным, а во вторых, очень часто после закрытия окна нужно сделать какие-то дополнительные действия, которые вам тоже придется как-то учитывать при каждом способе закрытия окна (а способов можно придумать сколько угодно, крестик, кнопка «закрыть», ссылка «закрыть» в тексте окна, нажатие вне окна).
Матерые программисты наверное скажут, что нужно создавать класс и наследовать его для каждого типа всплывающего окошка, переопределяя методы скрытия и показа. Но я бы хотел предложить другой путь как все это структурировать и избежать каши в коде и в голове. Если вы прочитали заголовок и текст до хабраката (а есть такие, кто не прочел?), наверное уже догадались, что именно я хочу предложить.
Я подготовил небольшой пример, в котором как раз представлены 2 подхода. Код первого, без использования событий, находится в блоке <div id="not-envents">. Второй, соответственно, в <div id="envents">.
Что я хотел показать первым примером:
Естественно, все что я описал, это только пример того, какие проблемы могут решить пользовательские события, на самом деле область их применения не ограничивается одним всплывающим окном.
$(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">.
Что я хотел показать первым примером:
- Смешано то, что называется «логикой» и «представлением», в одном месте определяется что должно происходить и как это должно делаться
- Когда понадобилось сделать .another-link1 (который гипотетически находится вообще в другом файле, просто должен открывать то же самое окно), пришлось повторить весь код, отвечающий за показ
- Когда понадобилось сделать ссылку в «Window 2», закрывающую окно прямо в тексте, пришлось повторить код, отвечающий за скрытие. Причем это простейший случай, все могло быть намного хуже.
- Можно выделить какие-то общие элементы для всех всплывающих окон и написать их логику в одном месте, что и показано на примере кнопки .close
- «Представление» (та часть, которая говорит как именно должно прятаться окно) полностью отделено от логики. Причем, конечно, название «представление» тут более чем условное. Очень часто может понадобиться при появлении окна показывать какие-то дополнительные элементы, а при скрытии прятать.
- Все события, навешанные на элементы (.link1, .link2, .link3) четко говорят, что нужно делать, но ничего не говорят о том, как это нужно делать.
- Код ссылки в тексте в «Window 2» также говорит только то, что окно должно быть спрятано. Если то, каким образом оно должно прятаться, изменится, нам не придется править ссылку в «Window 2».
- Наконец, становиться возможным сделать ссылку «.closeall», которая также ничего не знает о том, как будут прятаться окна. Даже на такой простой страничке видно, что создание кнопки «.closeall» для первого варианта — что-то из разряда фантастики.
Естественно, все что я описал, это только пример того, какие проблемы могут решить пользовательские события, на самом деле область их применения не ограничивается одним всплывающим окном.