Diferença entre as funções jQuery `click`,` bind`, `live`,` delegate`, `trigger` e` on` (com um exemplo)?

139

Eu li a documentação de cada função jQuery official website, mas não há tais listagens de comparação entre as funções abaixo:

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

Por favor, evite qualquer link de referência.

Como todas as funções acima funcionam exatamente e quais devem ser preferidas em qual situação?

Nota: Se houver outras funções com a mesma funcionalidade ou mecanismo, por favor, elabore.

Atualizar

Eu também vi uma $.triggerfunção. Funciona de maneira semelhante às funções acima?

Mais atualização

Agora .oné adicionado na v1.7 e acho que este, de alguma forma, cobre todos os requisitos de funções acima juntos.

diEcho
fonte
3
@I Como o PHP, às vezes as pessoas votam para baixo se não consideram uma pergunta que não pode ser respondida por um manual ou parece ser uma pergunta de lição de casa. não se preocupe, outras pessoas votarão se acharem útil.
typeoneerror
@ Typeoneerror - Obrigado pelo apoio, eu já li o manual e quando não entendi a diferença clara, posto aqui.
diEcho
3
@ Gosto de PHP - Editada a pergunta para um pouco de limpeza ... isso é frequentemente solicitado, mas raramente dessa maneira, pode ser facilmente um recurso valioso para o Google. Concordo que uma entrada wiki-ish de algo assim seria muito útil, vejo confusão em torno disso, especialmente com .live()e .delegate()quase todos os dias, +1 para uma pergunta perfeitamente válida.
Nick Craver
@ Nick Craver Obrigado pela edição, na verdade eu sou ruim em inglês (lol). Existe alguma referência / maunal sobre como postar uma pergunta SO. ot que veio apenas pela experiência
diEcho
@I Like PHP - É um pouco dos dois, há uma grande FAQ geral para SO aqui: meta.stackexchange.com/questions/7931 Para os fraseados / comentários, você começa a aprender o que se encaixa e é a melhor maneira de transmita seus pensamentos, codifique qualquer descrição algumas vezes, usando a palavra-chave certa, etiquetando de forma apropriada, apenas chega quanto mais você estiver aqui, suponho, vejo muitos pôsteres melhorando com o tempo. Quanto à sua edição, .trigger()basta chamar o manipulador de eventos ... adicionarei uma descrição à minha resposta abaixo.
Nick Craver

Respostas:

162

Antes de ler isso, puxe esta lista de eventos para outra página, a própria API é tremendamente útil e tudo o que estou discutindo abaixo está vinculado diretamente a esta página .

Primeiro, .click(function)é literalmente um atalho para .bind('click', function), eles são equivalentes. Use-os ao vincular um manipulador diretamente a um elemento , assim:

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

Se esse elemento for substituído ou jogado fora, esse manipulador não estará mais lá. Também os elementos que não estavam presentes quando esse código foi executado para anexar o manipulador (por exemplo, o seletor o encontrou) não receberão o manipulador.

.live()e .delegate()são parecidos, .delegate()na verdade usam .live()internamente; ambos escutam os eventos borbulharem. Isso funciona para elementos novos e antigos , eles exibem eventos da mesma maneira. Você os usa quando seus elementos podem mudar, por exemplo, adicionando novas linhas, itens de lista, etc. Se você não possui um ancestral pai / comum que permanecerá na página e não será substituído a qualquer momento, use o .live()seguinte:

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

Se, no entanto, você tiver um elemento pai em algum lugar que não está sendo substituído (para que seus manipuladores de eventos não estejam se despedindo), você deve lidar com .delegate()isso da seguinte maneira:

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

Isso funciona quase da mesma forma que .live(), mas o evento borbulha menos vezes antes de ser capturado e os manipuladores executados. Outro uso comum de ambos é dizer que sua classe é alterada em um elemento, não correspondendo mais ao seletor usado originalmente ... com esses métodos, o seletor é avaliado no momento do evento , se corresponder, o manipulador será executado. .são o elemento que não corresponde mais ao seletor importa, ele não será mais executado. No .click()entanto, o manipulador de eventos é vinculado diretamente ao elemento DOM, o fato de não corresponder a qualquer seletor usado para encontrá-lo é irrelevante ... o evento é vinculado e permanece até o elemento desaparecer, ou o manipulador é removido via .unbind().

Outro uso comum para .live()e .delegate()é o desempenho . Se você estiver lidando com muitos elementos, anexar um manipulador de cliques diretamente a cada elemento é caro e demorado. Nesses casos, é mais econômico configurar um único manipulador e deixar que o bubbling faça o trabalho, dê uma olhada nesta pergunta em que fez uma enorme diferença , é um bom exemplo da aplicação.


Disparo - para a pergunta atualizada

Existem duas funções principais de acionador de manipulador de eventos disponíveis, elas se enquadram na mesma categoria "Anexo de manipulador de eventos" na API , são .trigger()e .triggerHandler(). .trigger('eventName')possui alguns atalhos internos para os eventos comuns, por exemplo:

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

Você pode ver uma lista incluindo esses atalhos aqui .

Quanto à diferença, .trigger()aciona o manipulador de eventos (mas não a ação padrão na maioria das vezes, por exemplo, colocando o cursor no ponto certo em um clique <textarea>). Isso faz com que os manipuladores de eventos ocorram na ordem em que foram vinculados (como seria o evento nativo), aciona as ações do evento nativo e borbulha o DOM.

.triggerHandler()geralmente é para um propósito diferente, aqui você está apenas tentando disparar o (s) manipulador (es) vinculado (s), não causa o disparo do evento nativo, por exemplo, enviando um formulário. Ele não faz bolhas no DOM e não pode ser encadeado (ele retorna o que o último manipulador de eventos associado a esse evento retornar). Por exemplo, se você deseja acionar um focusevento, mas não focar o objeto, apenas deseja .focus(fn)executar o código vinculado , isso faria isso, enquanto o .trigger()faria, além de focar o elemento e fazer bolhas.

Aqui está um exemplo do mundo real:

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

Isso executaria quaisquer manipuladores de envio, por exemplo, o plug-in de validação do jQuery e tentaria enviar o <form>. No entanto, se você apenas deseja validar, uma vez que é conectado por meio de um submitmanipulador de eventos, mas não o envia <form>posteriormente, você pode usar o .triggerHandler('submit')seguinte:

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

O plug-in impede que o manipulador envie o formulário bombardeando se a verificação de validação não for aprovada, mas com esse método não nos importamos com o que faz. Independentemente de ter sido anulado ou não, não estamos tentando enviar o formulário, só queremos acioná-lo para re-validar e não fazer mais nada. ( Isenção de responsabilidade: este é um exemplo supérfluo, pois existe um .validate()método no plug-in, mas é uma ilustração decente da intenção)

Nick Craver
fonte
Muito completo. Uma pequena correção: triggernão dispara um evento nativo. Por nativo, quero dizer um evento simulado com fireEvent(IE) ou dispatchEvent(w3c).
Crescent Fresh
@Crescent - Atualizado a ser menos ambíguo, eu quis dizer que ele aciona o evento nativas ações , como o envio de formulários, ligação seguinte etc ... espero que a atualização é mais clara :)
Nick Craver
@ Nick pelo que estou lendo, parece que sua opinião live()é diferente daquela que você me deu aqui: stackoverflow.com/questions/3981762/… 'peso' ainda é uma preocupação ao usar live()?
Yahel
@ yahelc - Sim, é claro ... essa resposta está comparando estritamente as opções dos manipuladores de eventos e seu objetivo específico. O custo de ponderação versus o número de ligações iniciais vs. se você estiver adicionando algo dinamicamente ao seletor inicial ainda são preocupações válidas. Se você é a estrutura da página não é que grande você não tem que muitos eventos, em seguida, você está bem ... a preocupação com o peso é diretamente proporcional ao tamanho / profundidade de sua estrutura e o número de eventos (de o tipo pelo qual sua .live()chamada escuta, por exemplo click) que está sendo gerada, pois executa seletores para cada um.
Nick Craver
1
no jQuery 1.7, live () é preterido em favor de $ (document) .on ().
Synchro 23/11
28

Os dois primeiros são equivalentes.

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

O segundo, no entanto, pode ser usado para vincular a mais de um evento ao mesmo tempo, especificando vários nomes de eventos separados por espaço:

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

O .livemétodo é mais interessante. Considere o seguinte exemplo:

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

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

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

Após a execução da segunda linha do script, o segundo link também terá uma classe CSS de "myLink". Mas ele não terá o manipulador de eventos, porque não tinha a classe quando o evento foi anexado.

Agora, considere que você deseja que seja o contrário: sempre que um link com a classe "myLink" aparecer em algum lugar da página, você deseja que ele tenha o mesmo manipulador de eventos automaticamente. Isso é muito comum quando você tem algum tipo de lista ou tabela, na qual adiciona linhas ou células dinamicamente, mas deseja que todas elas se comportem da mesma maneira. Em vez de se esforçar para atribuir manipuladores de eventos novamente, você pode usar o .livemétodo:

<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>

Neste exemplo, o segundo link também obterá o manipulador de eventos assim que receber a classe "myLink". Magia! :-)

Claro, não é tão literal. o que.live realmente faz é anexar o manipulador não ao elemento especificado em si, mas à própria raiz da árvore HTML (o elemento "body"). Eventos em DHTML têm esse recurso engraçado de "borbulhar". Considere isto:

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

Se você clicar em "texto", primeiro o elemento <b> receberá um evento "clique". Depois disso, o elemento <a> receberá um evento "click". E depois disso, o elemento <div> receberá um evento "click". E assim por diante - até o elemento <body>. E é aí que o jQuery captura o evento e verifica se existem manipuladores "ativos" que se aplicam ao elemento que causou o evento em primeiro lugar. Arrumado!

E, finalmente, o .delegatemétodo. Ele simplesmente pega todos os filhos do seu elemento que estão em conformidade com o seletor fornecido e anexa um manipulador "ativo" a eles. Dê uma olhada:

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

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

Questões?

Fyodor Soikin
fonte
Para ser preciso, .live()vincule-se a documentnão <body>:) Você pode ver uma demonstração aqui, basta abrir o console para inspecionar: jsfiddle.net/aJy2B
Nick Craver
3
Era mais conveniente explicar dessa maneira. :-)
Fyodor Soikin
4
É justo o suficiente na parte "body", mas "todo o caminho até o elemento <body>" está errado, os eventos continuam passando por lá e não é onde .live()vivem os manipuladores, é acima disso, no document:) Você pode ver um demonstração disso aqui: jsfiddle.net/S2VBX
Nick Craver
8

A partir do jQuery 1.7, o método .live () foi preterido. Se você estiver usando uma versão do jQuery <1.7, é recomendável usar oficialmente .delegate () sobre .live ().

.live () agora foi substituído por .on ().

É melhor ir diretamente ao site jQuery para obter mais informações, mas aqui estão as versões atuais do método .on ():

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

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

Jonathan Tonge
fonte
2

$().click(fn)e $().bind('click', fn)são idênticos à primeira vista, mas a $.bindversão é mais poderosa por dois motivos:

  1. $().bind()permite atribuir um manipulador a vários eventos, por exemplo $().bind('click keyup', fn),.
  2. $().bind()suporta eventos com espaço para nome - um recurso poderoso se você deseja remover (desvincular) apenas determinados manipuladores de eventos aos quais um elemento está vinculado - leia mais em Eventos com espaço para nome .

Live vs delegate: isso já foi respondido nas outras respostas.

fbuchinger
fonte
1

É aqui que a leitura da API pode ajudar. No entanto, eu sei do alto da minha cabeça, para que você possa continuar sendo preguiçoso (yay!).

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

Não há diferença aqui (que eu saiba). .clické simplesmente um método de conveniência / auxiliar para.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);

Isso é muito diferente, pois .liveadiciona eventos ao seletor que você passa (o que você não tem aqui) e continua a olhar para o DOM conforme os nós são inseridos / removidos

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

Isso é diferente apenas pela maneira como você está atribuindo manipuladores de eventos. .delegateestá centralizado no evento DOM borbulhante. O princípio básico é que todo evento borbulha para cima através da árvore do DOM até atingir o elemento raiz ( documentou windowou <html>ou <body>, não me lembro exatamente).

De qualquer forma, você está vinculando um onclickmanipulador a todos os <td>s dentro $('#some_element')(você deve especificar um seletor, embora possa dizer $(document)). Quando um de seus filhos é clicado, o evento borbulha até o <td>. Você pode extrair o elemento de origem do evento (o que o jQuery faz por você automaticamente).

Isso é útil quando existem muitos elementos e você tem apenas alguns pontos (ou um ponto central) pelos quais esses eventos serão submetidos. Isso economiza o esforço e a memória do navegador para consolidar esses manipuladores de eventos em menos objetos.

Dan Beam
fonte
1
.live() Também funciona off subida do evento, na verdade .delegate()é um wrapper para .live(), é apenas a adição de um contexto e de ligação a um elemento diferente do que documentpara capturar as bolhas. Eu acho que a sua compreensão de como os manipuladores borbulhantes funcionam é um pouco difícil (esse é o aspecto mais incompreendido do jQuery 1.4, eu acho). O manipulador está apenas no elemento ao qual você o vinculou, portanto, qualquer elemento que você chamou .delegate()ou, documentno caso de .live(), quando um evento borbulha para lá, ele verifica o destino para ver se ele corresponde ao seletor e se é executado.
Nick Craver