Разница между функциями jQuery `click`,` bind`, `live`,` delegate`, `trigger` и ʻon` (с примером)?

140

Я прочитал документацию по каждой функции jQuery official website, но таких сравнительных списков между функциями ниже нет:

$().click(fn)
$().bind('click',fn)
$().live('click',fn)
$().delegate(selector, 'click', fn)
$().trigger('click') // UPDATED
$().on('click', selector ,fn); // more UPDATED

Избегайте ссылок на ссылки.

Как именно работают все вышеперечисленные функции и какие из них следует предпочесть в какой ситуации?

Примечание. Если есть какие-либо другие функции, имеющие такую ​​же функциональность или механизм, просьба уточнить.

Обновить

Я тоже видел $.triggerфункцию. Работает ли он аналогично вышеуказанным функциям?

Больше обновлений

Теперь .onон добавлен в v1.7, и я думаю, что он каким-то образом покрывает все вышеперечисленные требования вместе.

diEcho
источник
3
@I Как и в случае с PHP, иногда люди голосуют против, если не считают, что это вопрос, на который нельзя ответить в руководстве или который кажется вопросом домашнего задания. не волнуйтесь, другие люди проголосуют за него, если сочтут его полезным.
typeoneerror 02
@ Typeoneerror - Спасибо за поддержку, я уже прочитал руководство, и когда я не понял четкой разницы, я публикую здесь.
diEcho 02
3
@I Like PHP - отредактировал вопрос для небольшой очистки ... это часто задают, но редко, так как это может легко быть ценным ресурсом для Google. Я согласен, что вики-запись чего-то вроде этого была бы очень полезной, я вижу путаницу вокруг этого, особенно .live()и .delegate()почти каждый день, +1 за совершенно правильный вопрос.
Ник Крейвер
@Nick Craver Спасибо за редактирование, на самом деле я плохо говорю по-английски (смеется). есть ли какие-либо ссылки / ссылки на то, как мы публикуем вопрос SO. не это просто на опыте
diEcho
@I Like PHP - это и то, и другое, здесь есть отличный всесторонний FAQ для SO: meta.stackexchange.com/questions/7931 Для формулировки / комментариев вы просто начинаете понимать, что подходит и является лучшим способом передавайте свои мысли, кодируйте> любое описание иногда, используя правильное ключевое слово, соответствующим образом помечая теги, просто чем дольше вы здесь, я полагаю, я вижу, что многие плакаты со временем улучшаются. Что касается вашего редактирования, .trigger()просто вызывает обработчик событий ... Я добавлю описание к своему ответу ниже.
Ник Крейвер

Ответы:

163

Прежде чем вы это прочитаете, перетащите этот список событий на другую страницу, сам API чрезвычайно полезен, и все, что я обсуждаю ниже, связано непосредственно с этой страницей .

Во-первых, .click(function)это буквально сокращение .bind('click', function), они эквивалентны. Используйте их при привязке обработчика непосредственно к элементу , например:

$(document).click(function() {
  alert("You clicked somewhere in the page, it bubbled to document");
});

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

.live()и .delegate()аналогичным образом связаны, .delegate()фактически используются .live()внутренне, они оба прослушивают всплытие событий. Это работает для новых и старых элементов , они всплывают события одинаково. Вы используете их, когда ваши элементы могут измениться, например, добавление новых строк, элементов списка и т. Д. Если у вас нет родительского / общего предка, который останется на странице и не будет заменен в какой-либо момент, используйте .live(), например:

$(".clickAlert").live('click', function() {
  alert("A click happened");
});

Однако если у вас где-то есть родительский элемент, который не заменяется (поэтому его обработчики событий не уходят до свидания), вы должны обработать его .delegate(), например:

$("#commonParent").delegate('.clickAlert', 'click', function() {
  alert("A click happened, it was captured at #commonParent and this alert ran");
});

Это работает почти так же .live(), но событие всплывает реже, прежде чем будет захвачено и обработчики выполнятся. Другое распространенное использование обоих из них - это сказать, что ваш класс изменяется в элементе, больше не соответствует селектору, который вы изначально использовали ... с этими методами селектор оценивается во время события , если он совпадает, обработчик запускается. . поэтому элемент, больше не соответствующий селектору, имеет значение, он больше не будет выполняться. С .click()однако, обработчик событий связан , прямо на элемент DOM, тот факт , что он не соответствует любой селектор был использован , чтобы найти его не имеет никакого отношения ... это событие неизбежно , и это пребывание , пока не исчезнет этот элемент, или обработчик удаляется через .unbind().

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


Запуск - для обновленного вопроса

Доступны 2 основные функции запуска обработчика событий, они подпадают под одну и ту же категорию «Присоединение обработчика событий» в API , это .trigger()и .triggerHandler(). .trigger('eventName')имеет несколько встроенных ярлыков для общих событий, например:

$().click(fn); //binds an event handler to the click event
$().click();   //fires all click event handlers for this element, in order bound

Вы можете просмотреть список, включающий эти ярлыки, здесь .

Что касается разницы, .trigger()запускает обработчик событий (но не действие по умолчанию большую часть времени, например, размещение курсора в нужном месте при нажатии <textarea>). Это заставляет обработчики событий происходить в том порядке, в котором они были связаны (как и собственное событие), запускает собственные действия событий и всплывает в DOM.

.triggerHandler()обычно для другой цели, здесь вы просто пытаетесь запустить связанный обработчик (-ы), это не приводит к срабатыванию собственного события, например, отправки формы. Он не всплывает в DOM и не объединяется в цепочку (он возвращает то, что возвращает обработчик последнего связанного события для этого события). Например, если вы хотите вызвать focusсобытие, но не сфокусировать объект, вам просто нужно, чтобы код, с .focus(fn)которым вы связаны, запускался, это будет делать это, тогда как .trigger()сделает это, а также фактически сфокусирует элемент и всплывет вверх.

Вот пример из реального мира:

$("form").submit(); //actually calling `.trigger('submit');`

Это запустит любые обработчики отправки, например плагин проверки jQuery , а затем попытается отправить файл <form>. Однако, если вы просто хотите проверить, поскольку он подключен через submitобработчик событий, но не отправляет его <form>впоследствии, вы можете использовать .triggerHandler('submit'), например:

$("form").triggerHandler('submit');

Плагин предотвращает отправку формы обработчиком, взрываясь, если проверка не проходит, но с этим методом нам все равно, что он делает. Независимо от того, прервано оно или нет, мы не пытаемся отправить форму, мы просто хотели запустить ее для повторной проверки и больше ничего не делать. ( Отказ от ответственности: это лишний пример, поскольку .validate()в плагине есть метод, но это достойная иллюстрация намерения)

Ник Крейвер
источник
Очень тщательно. Одно небольшое исправление: triggerне запускает собственное событие. Под родным я подразумеваю событие, моделируемое с помощью fireEvent(IE) или dispatchEvent(w3c).
Crescent Fresh
@Crescent - Обновлен, чтобы быть менее двусмысленным, я имел в виду, что он запускает собственные действия событий , такие как отправка форм, переход по ссылке и т. Д., Надеюсь, обновление более четкое :)
Ник Крейвер
@Nick, судя по тому, что я читаю, похоже, что ваш подход live()отличается от того, который вы мне дали здесь: stackoverflow.com/questions/3981762/… При использовании «вес» все еще вызывает беспокойство live()?
Yahel
@yahelc - Да, конечно ... этот ответ строго сравнивает параметры обработчиков событий и их конкретное назначение. Стоимость веса по сравнению с количеством начальных привязок по сравнению с динамическим добавлением чего-либо по сравнению с исходным селектором - все еще актуальные проблемы. Если вы структура страницы не что большой вы не имеете , что много событий , то все в порядке ... беспокойство по весу прямо пропорциональна размеру / глубины вашей структуры и количества событий (из тип, который .live()прослушивает ваш вызов, например click), которые генерируются, поскольку он запускает селекторы для каждого из них.
Ник Крейвер
1
в jQuery 1.7 live () устарел в пользу $ (document) .on ().
Synchro
28

Первые два эквивалентны.

// The following two statements do the same thing:
$("blah").click( function() { alert( "Click!" ); } );
$("blah").bind( "click", function() { alert( "Click!" ); } ); 

Второй вариант, однако, можно использовать для привязки к более чем одному событию одновременно, указав несколько имен событий, разделенных пробелами:

$("blah").bind( "click mouseover mouseout", function() { alert( "Click! Or maybe mouse moved." ); } ); 

.liveМетод является более интересным. Рассмотрим следующий пример:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").click( function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

После выполнения второй строки скрипта вторая ссылка также будет иметь CSS-класс «myLink». Но у него не будет обработчика события, потому что у него не было класса, когда событие было прикреплено.

Теперь представьте, что вы хотели, чтобы все было наоборот: каждый раз, когда где-то на странице появляется ссылка с классом «myLink», вы хотите, чтобы она автоматически имела тот же обработчик событий. Это очень часто бывает, когда у вас есть какие-то списки или таблицы, в которые вы добавляете строки или ячейки динамически, но хотите, чтобы все они вели себя одинаково. Вместо того, чтобы каждый раз заново назначать обработчики событий, вы можете использовать .liveметод:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").live( "click", function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

В этом примере вторая ссылка также получит обработчик событий, как только получит класс myLink. Магия! :-)

Конечно, это не так буквально. На .liveсамом деле обработчик прикрепляется не к самому указанному элементу, а к самому корню дерева HTML (элементу "body"). События в DHTML имеют забавную особенность «всплытия». Учти это:

<div> <a> <b>text</b> </a> </div>

Если вы нажмете на «текст», то сначала элемент <b> получит событие «клик». После этого элемент <a> получит событие «щелчок». И после этого элемент <div> получит событие «щелчок». И так далее - вплоть до элемента <body>. И именно здесь jQuery перехватит событие и увидит, есть ли какие-нибудь «живые» обработчики, которые применяются к элементу, который изначально вызвал событие. Аккуратно!

И наконец, .delegateметод. Он просто берет всех дочерних элементов вашего элемента, которые соответствуют данному селектору, и присоединяет к ним «живой» обработчик. Взглянем:

$("table").delegate( "td", "click", function() { alert( "Click!" ); } );

// Is equivalent to:
$("table").each( function() {
    $(this).find( "td" ).live( "click", function() { alert( "Click!" ); } );
} );

Вопросы?

Федор Сойкин
источник
Чтобы быть точным, .live()привязывается к documentнет <body>:) Вы можете просмотреть демонстрацию здесь, просто потяните консоль, чтобы проверить: jsfiddle.net/aJy2B
Nick Craver
3
Так было удобнее объяснять. :-)
Фёдор Сойкин
4
Достаточно справедливо в части "body", но "полностью до элемента <body>" неверно, события продолжают всплывать там, и .live()обработчики живут не там , а над ним document:) Вы можете увидеть Демонстрация этого здесь: jsfiddle.net/S2VBX
Ник
8

Начиная с jQuery 1.7, метод .live () устарел. Если вы используете jQuery версии <1.7, то официально рекомендуется использовать .delegate () вместо .live ().

.live () теперь заменен на .on ().

Для получения дополнительной информации лучше всего перейти непосредственно на сайт jQuery, но вот текущие версии метода .on ():

.on( events [, selector] [, data], handler(eventObject) )
.on( events-map [, selector] [, data] )

http://api.jquery.com/on/

Джонатан Тонг
источник
2

$().click(fn)и $().bind('click', fn)на первый взгляд идентичны, но $.bindверсия более мощная по двум причинам:

  1. $().bind()позволяет назначить один обработчик нескольким событиям, например $().bind('click keyup', fn).
  2. $().bind()поддерживает события с пространством имен - мощная функция, если вы хотите удалить (отменить привязку) только определенные обработчики событий, к которым привязан элемент - подробнее см. События с пространством имен .

Live vs delegate: на это уже был дан ответ в других ответах.

Fbuchinger
источник
1

Здесь может помочь чтение API. Тем не менее, я знаю это с головы до ног, так что вы можете продолжать лениться (ура!).

$('#something').click(fn);
$('#something').bind('click',fn);

Здесь нет никакой разницы (насколько я знаю). .clickпросто удобный / вспомогательный метод для.bind('click'

// even after this is called, all <a>s in
// <div class="dynamic_els"> will continue
// to be assigned these event handlers

$('div.dynamic_els a').live(‘click’,fn);

Это очень отличается, поскольку .liveдобавляет события к селектору, который вы передаете (которого у вас здесь нет), и продолжает смотреть на DOM, когда узлы вставляются / удаляются.

$('#some_element').delegate('td','click',fn);

Это отличается только из-за способа назначения обработчиков событий. .delegateсосредоточен на всплытии событий DOM. Основной принцип заключается в том, что каждое событие всплывает вверх по дереву DOM, пока не достигнет корневого элемента ( documentили windowили <html>или <body>, я не могу точно вспомнить).

В любом случае вы привязываете onclickобработчик ко всем <td>элементам внутри $('#some_element')(вы должны указать селектор, хотя можно было бы сказать $(document)). При щелчке по одному из его дочерних элементов событие всплывает до <td>. Затем вы можете извлечь исходный элемент события (что jQuery делает за вас автоматически).

Это полезно, когда есть множество элементов, и у вас есть только несколько (или одна центральная) точка (точки), через которые будут проходить эти события. Это экономит усилия браузера и память для объединения этих обработчиков событий в меньшее количество объектов.

Дэн Бим
источник
1
.live() также отрабатывает восходящую цепочку события, на самом деле .delegate()является оберткой .live(), это просто добавить контекст и привязку к элементу другому , чем documentзахватить пузыри. Я думаю, что ваше понимание того, как работают обработчики пузырьков, немного не так (я думаю, это наиболее часто неправильно понимаемый аспект jQuery 1.4). Обработчик находится только на элементе, к которому вы его привязываете, поэтому какой бы элемент вы ни вызывали .delegate(), или documentв случае .live(), когда событие переходит туда, он проверяет цель, чтобы увидеть, соответствует ли она селектору, и если да, то выполняется.
Ник Крейвер