На
работе столкнулись с “особенностью” работы
jQuery.live(),
на которую хотелось бы обратить внимание, потому как, судя по всему,
отнюдь не все о ней знают (и в результате чего пишут неработающий код).
Итак, простой пример - навешивание двух событий на один и тот же элемент:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<title>jQuery.live() test pagetitle>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">script>
<script type="text/javascript">
jQuery(function() {
$("a").bind("click", function(e) {
alert("a");
return false;
});
$("a").bind("click", function(e) {
alert("b");
return false;
});
});
script>
head>
<body>
<a href="http://blog.fxposter.org/">Блог FX-аa>
body>
html>
Пример можно посмотреть
здесь. В результате клика на ссылку - получаем 2 alert-а, всё хорошо, ожидаемо и предсказуемо.
Переписываем код для работы с jQuery.live(). Для тех, кто в танке -
live() вешает событие не на сам элемент, а на document. В результате
bubbling-а событие, которое произошло над каким-либо элементом поднимается вверх по
DOM-дереву
и соответственно вызывает обработчики всех элементов, которые оно
встретит. Если вы и этого не знали - то вам не нужно читать мой блог, а
пора идти и покупать книгу по JavaScript-у (мне, кстати, тоже давно
пора, но всё никак не соберусь). Итак, в конце концов событие доходит до
document-а и обработчики вызываются у него. Обработчик, который
устанавливает jQuery.live() проверяет - соответствует ли event.target (а
именно здесь хранится обьект DOM-дерева, с которым произошло событие)
соответствующему селектору (в данном случае - это селектор “a”) и если
соответствует - то выполняет обработчик.
Преимущества и недостатки - это тема отдельной статьи. Если не
уклонятся в сторону оптимизации, то основным преимуществом, на мой
взгляд, является тот факт, что обработчики, навешенные live()-ом будут
запускаться даже для элементов, которые были динамически добавлены на
страницу, в отличии от
bind()-обработчиков,
которые на эти элементы нужно будет навешивать вручную (если непонятно,
почему это работает именно так - читаем предыдущий абзац, если все
равно непонятно - идем покупать всё ту же книгу).
Далее - зачем нужен “return false” в конце обработчика? Он
предотвращает от того, чтобы вызывалось действие по умолчанию (в данном
случае - переход по ссылке и событие не поднималось выше). Чаще всего
JS-разработчики вообще не думают о bubbling-е и под “return false”
понимают только “отмену действия по умолчанию”, ну или они вообще не
знают, что именно происходит и пишут “return false”, потому что так
работает.
Такое отношение jQuery частенько прощает. Но не в случае с live()-методом. Попробуем запустить следующий
пример:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<title>jQuery.live() test pagetitle>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">script>
<script type="text/javascript">
jQuery(function() {
$("a").live("click", function(e) {
alert("a");
return false;
});
$("a").live("click", function(e) {
alert("b");
return false;
});
});
script>
head>
<body>
<a href="http://blog.fxposter.org/">Блог FX-аa>
body>
html>
В результате клика теперь выскакивает только один alert. Пора обратится к
документации:
# To stop further handlers from executing after one bound
using .live(), the handler must return false. Calling
.stopPropagation() will not accomplish this.
Хаха. В данном случае jQuery интерпретирует false “несколько иначе”. :)
Для того, чтобы “пофиксить” подобный баг нужно обратится все к тому
же bubbling-у и обработке событий и сделать именно то, что
предполагается разработчиком - “отменить действие по умолчанию”. Это
делается с помощью метода
event.preventDefault() (
пример):
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<title>jQuery.live() test pagetitle>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">script>
<script type="text/javascript">
jQuery(function() {
$("a").live("click", function(e) {
alert("a");
e.preventDefault();
});
$("a").live("click", function(e) {
alert("b");
e.preventDefault();
});
});
script>
head>
<body>
<a href="http://blog.fxposter.org/">Блог FX-аa>
body>
html>
И самое главное (барабанная дробь!) - при использовании bind() для
навешивания обработчиков preventDefault() тоже можно использовать!
Наткнулись мы на эту “фичу”, когда у нас почему-то перестали вызываться
некоторые обработчики
Напоследок, замечу еще одно - элемент, на который навешено хотя бы
один обработчик события через bind() с “правильно работающим return
false”, никогда не будет вызывать никакие live()-события. ;)
Источник