Método jQuery .live () vs .on () para adicionar um evento de clique após carregar o html dinâmico

216

Estou usando o jQuery v.1.7.1, onde o método .live () é aparentemente obsoleto.

O problema que estou tendo é que, ao carregar dinamicamente o html em um elemento usando:

$('#parent').load("http://..."); 

Se eu tentar adicionar um evento de clique depois, ele não registrará o evento usando um destes métodos:

$('#parent').click(function() ...); 

ou

// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...); 

Qual é a maneira correta de obter essa funcionalidade? Apenas parece funcionar com .live () para mim, mas eu não deveria estar usando esse método. Observe que #child é um elemento carregado dinamicamente.

Obrigado.

Sean Thoman
fonte
25
Por que você diz "supostamente reprovado" ? Você não acredita nos documentos?
6
Não é supostamente obsoleto: está obsoleto. Se você olhar para o documento do jQuery,.live() ele mostra como reescrever os usos existentes de .live()usar .delegate()ou .on()(dependendo se você está na versão 1.7+ ou não). Observe, porém, que se você adicionar um manipulador com .click()"depois", como você mencionou, ou seja, depois de carregar elementos dinamicamente, ele deverá funcionar - o único problema é tentar atribuir .click() antes de carregar elementos dinamicamente.
Nnnnnn
Mudei a redação para 'aparentemente', já que era basicamente isso que eu queria dizer. De qualquer forma, agora entendo que, obviamente, como o evento .load () é assíncrono, o elemento #child só pode ser reconhecido de maneira confiável no manipulador de sucesso, o que faz sentido.
Sean Thoman
Possível duplicata da associação
showdev 10/08/16

Respostas:

606

Se você deseja que o manipulador de cliques funcione para um elemento carregado dinamicamente, defina o manipulador de eventos em um objeto pai (que não seja carregado dinamicamente) e dê a ele um seletor que corresponda ao seu objeto dinâmico como este:

$('#parent').on("click", "#child", function() {});

O manipulador de eventos será anexado ao #parentobjeto e, sempre que um evento de clique aparecer na origem #child, ele acionará o manipulador de cliques. Isso é chamado de manipulação de eventos delegados (a manipulação de eventos é delegada a um objeto pai).

Isso é feito dessa maneira porque você pode anexar o evento ao #parentobjeto, mesmo quando o #childobjeto ainda não existe, mas, quando ele existir mais tarde e for clicado, o evento click passará para o #parentobjeto, verá que ele foi originado #childe existe um manipulador de eventos para clicar #childe acionar seu evento.

jfriend00
fonte
23
Ótima explicação! Eu nunca antes foi capaz de envolver minha cabeça em torno live()vs. on()mas esta noite eu decidi mais uma vez para tentar, e sua explicação revelou imediatamente que eu tinha faltado o tempo todo. Obrigado!
MikeSchinkel #
6
Um milhão de ups . Comecei a usar o nocaute antes de perceber que isso era possível no jQuery para crianças criadas dinamicamente, muito obrigado.
Brock Hensley
9
Você deve escrever um livro ou algo assim: seu pequeno texto foi mais útil para mim do que a página inteira nos documentos do jQuery sobre « on () ». Muito obrigado!
Colesterol
@ jfriend00 você sabe como podemos aplicar esse mesmo processo a uma situação de foco e não-foco? existe uma fonte que fala sobre isso?
klewis
@blackhawk - Veja esta resposta . Você pode se inscrever para os mouseentere mouseleaveeventos e teste dentro do manipulador qual foi desencadeada. O evento pseudo "pairar" do jQuery não está disponível com delegação.
precisa saber é
33

Tente o seguinte:

$('#parent').on('click', '#child', function() {
    // Code
});

A partir da $.on()documentação:

Os manipuladores de eventos são vinculados apenas aos elementos selecionados no momento; eles devem existir na página no momento em que seu código faz a chamada .on().

Seu #childelemento não existe quando você o chama $.on(), portanto o evento não é vinculado (ao contrário $.live()). #parent, No entanto, faz existir, então a ligação do evento para que é bom.

O segundo argumento no meu código acima funciona como um 'filtro' apenas gatilho se o evento borbulhava a #parentpartir #child.

Bojangles
fonte
Se eu chamar o método $ .on () após o método $ .load (), por que o elemento #child não existiria nesse momento?
9788 Sean Thomman
6
@SeanThoman - você teria que chamá-lo do manipulador de sucesso do .load()método - e não do código após o .load()método. #childsó é conhecido por ser carregado quando o manipulador de sucesso realmente é executado e não antes.
precisa saber é
e mesmo assim, o tempo necessário para inserir quaisquer dados que você retornou ao DOM significa que eles podem não se conectar. Ultimamente, tenho trabalhado bastante em aplicativos de página única e meu padrão é var $ body = $ ('body'); $ body.on ("evento", ". elemento / # classe", function (e) {}); para tudo. 1 seletor. Não se preocupe com o que está ou não está carregado.
lupos
21

$(document).on('click', '.selector', function() { /* do stuff */ });

EDIT: Estou fornecendo um pouco mais de informações sobre como isso funciona, porque ... palavras. Com este exemplo, você está colocando um ouvinte em todo o documento.

Quando você clickcombina com qualquer elemento (s) .selector, o evento borbulha até o documento principal - desde que não haja outros ouvintes que chamam event.stopPropagation()método - que superariam a subida de um evento aos elementos pai.

Em vez de vincular-se a um elemento ou conjunto de elementos específico, você está atendendo a eventos provenientes de elementos que correspondem ao seletor especificado. Isso significa que você pode criar um ouvinte, uma vez, que corresponderá automaticamente aos elementos existentes atualmente, bem como aos elementos adicionados dinamicamente.

Isso é inteligente por alguns motivos, incluindo desempenho e utilização de memória (em aplicativos de grande escala)

EDITAR:

Obviamente, o elemento pai mais próximo que você pode ouvir é melhor, e você pode usar qualquer elemento no lugar document, desde que os filhos para os quais deseja monitorar eventos estejam dentro desse elemento pai ... mas isso realmente não tem nada a ver com a pergunta.

L422Y
fonte
23
Ele tentou $(element).on(...). Isto é $(document).on(...,element,...). Bestas diferentes.
cHao 6/01/12
@ArnoldRoa sim, melhor desempenho. você não terá um ouvinte em vários filhos, não precisará reaplicá-lo sempre que o DOM for modificado e os eventos aparecerão através do DOM por padrão. Executar uma vez e todos os filhos correspondentes ao seletor acionarão a função fornecida quando clicados.
L422Y
O comentário de @ L422Y aqui é muito enganador. Se você está curioso sobre implicações de desempenho, dê uma olhada @ de jfriend00 comentário sobre @ resposta de Jared
Gust van de Wal
@GustvandeWal Como isso é enganador? Se você emitir cem $ (isto). Em (...) vs escutar um evento uma vez em um elemento pai, é substancialmente mais eficiente.
L422Y 2/10/19
Você está falando apenas de anexar os eventos. Os gargalos de desempenho do mundo real são muitos ouvintes disparando (como aqueles que você delega), não grandes quantidades de elementos que precisam de um evento associado a eles.
Gust van de Wal
12

O equivalente a .live () em 1.7 é assim:

$(document).on('click', '#child', function() ...); 

Basicamente, assista ao documento para eventos de clique e filtre-os para #child.

Jared
fonte
Porque é assim que o manipulador de eventos se anexa ao documento (da mesma maneira .live()).
cHao 6/01/12
17
Um motivo que .live()foi descontinuado agora é porque é ruim colocar todos os manipuladores de eventos ao vivo no objeto de documento. As coisas podem muito, muito devagar. Não apenas os eventos precisam chegar até o documento, mas você pode ter muitos manipuladores de eventos para examinar o objeto do documento. A principal vantagem .on()é que você pode anexá-lo a um objeto pai muito mais próximo do objeto real e melhorar drasticamente o desempenho. Então ... eu não recomendaria o uso .on()com o objeto de documento. Muito melhor escolher um objeto pai mais próximo.
jfriend00
Obrigado pelo esclarecimento. Pelo que vale a pena, o desempenho dos eventos foi muito melhorado com on (), por isso deve ser um problema menor do que costumava ser. Se você se anexar a um pai, presumiria que ele teria que ser um pai existente no documento pronto ou você teria problemas semelhantes.
Jared
Na pior das hipóteses, isso não emular o preterido .live()abordagem; no entanto, a capacidade de controlar a delegação é certamente vantajosa.
precisa
9

Eu sei que é um pouco tarde para uma resposta, mas eu criei um polyfill para o método .live (). Eu testei no jQuery 1.11 e parece funcionar muito bem. Eu sei que devemos implementar o método .on () sempre que possível, mas em grandes projetos, onde não é possível converter todas as chamadas .live () para as chamadas equivalentes .on () por qualquer motivo, o seguinte pode trabalhos:

if(jQuery && !jQuery.fn.live) {
    jQuery.fn.live = function(evt, func) {
        $('body').on(evt, this.selector, func);
    }
}

Basta incluí-lo depois de carregar o jQuery e antes de ligar para live ().

NSV
fonte
5

.on () é para o jQuery versão 1.7 e superior. Se você possui uma versão mais antiga, use o seguinte:

$("#SomeId").live("click",function(){
    //do stuff;
});
Matt Cashatt
fonte
8
O OP diz "Estou usando o jQuery v.1.7.1"
Selvakumar Arumugam
1
@ jfriend - por que não postar sua própria resposta em vez de diminuir a minha? Eu uso live () todos os dias com todas as versões menores que 1.6 e funciona bem. Percebo que você é bom em ler documentação, mas às vezes é mais útil colocar algo em prática para uma pessoa. .live () funciona. Período.
Matt Cashatt
5
@MatthewPatrickCashatt - eu postei minha própria resposta e não reduzi a sua - não faça suposições cegas. Antes da versão 1.7, o .delegate()desempenho é muito melhor do .live()que o motivo pelo qual o documento do jQuery recomenda e desaprova .live(). Sim, .live()ainda funciona, mas as respostas aqui no SO devem recomendar a melhor maneira de fazer as coisas. Eu já vi isso 20 vezes aqui no SO. Se você postar o código .live()aqui no SO, ele será votado novamente (normalmente não por mim, a menos que haja algo mais errado com ele).
jfriend00
1
Não diminuí a votação, mas, embora .live()definitivamente funcione mesmo na versão 1.7, você ainda deve usar .delegate()ou .on()porque .live()foi preterido por um bom motivo. Contanto que você observe a alteração na sintaxe das duas funções mais recentes, elas funcionarão bem.
Nnnnnn
1
@ jfriend00- Você está absolutamente certo. Longo dia. Me desculpe.
Matt Cashatt
3

Eu usei 'live' no meu projeto, mas um amigo sugeriu que eu deveria usar 'on' em vez de live. E quando tentei usar isso, tive um problema como você.

Nas minhas páginas, crio linhas de tabelas de botões e muitas coisas dinamicamente. mas quando eu uso a magia desapareceu.

As outras soluções, como usá-lo como uma criança, apenas chamam suas funções todas as vezes a cada clique. Mas eu acho uma maneira de fazer isso acontecer novamente e aqui está a solução.

Escreva seu código como:

function caller(){
    $('.ObjectYouWntToCall').on("click", function() {...magic...});
}

Chamador (); depois de criar seu objeto na página assim.

$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();

Dessa forma, sua função é chamada quando é suposto que nem todos os cliques na página.

Coderx07
fonte