evento de ligação apenas uma vez

104

Eu tenho o seguinte código:

function someMethod()
{
  $(obj).click(function {});
}

someMethod é chamado duas vezes e, portanto, o evento de clique é vinculado duas vezes. Como posso vinculá-lo apenas uma vez?

pássaro de fogo
fonte

Respostas:

190

Se você puder aplicá-lo, provavelmente queira dar uma olhada em event.preventDefault e event.stopPropagation OU desvincular e vincular a cada vez, dentro de seu método, como

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}
pna
fonte
19
Tenha cuidado, porque isso desassocia TODOS os eventos de clique e nem sempre é o comportamento desejado. Por exemplo, ao vincular algo a um documento, você deseja desvincular apenas aquele evento, não todos eles.
Mārtiņš Briedis
26
Caso você não queira desvincular acidentalmente outros eventos de clique, você pode usar function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu
@Manu você copiou desta resposta
aexl
89

Além da resposta de pna, você pode querer pensar sobre o namespace de seu evento para não desvincular todos os eventos de clique acidentalmente.

function someMethod () {
    $ (obj) .unbind ('click.namespace'). bind ('click.namespace', function () {});
}

https://api.jquery.com/event.namespace/

Iain
fonte
10
Esta deve ser a resposta aceita. Desvincular todos os eventos de clique pode quebrar as coisas facilmente - especialmente se for um projeto complexo com muito jQuery acontecendo. Obrigado por isso! Não sabia sobre esta solução de namespace simples !!
Simon Steinberger
Com o jQuery atual, deve ser $(obj).off()e $(obj).on()respectivamente. Caso contrário, o namespacing ajudou e funcionou. Obrigado!
aexl
19

Não existe um método integrado para determinar se você já vinculou esta função específica. Você pode vincular várias funções de clique a um objeto. Por exemplo:

$('#id').bind('click', function(){
alert('hello');
});


$('#id').bind('click', function(){
alert('goodbuy');
});

se você fizer o acima quando o objeto for clicado, ele irá alertá-lo. Para garantir que apenas uma função esteja associada ao evento click, desassocie o manipulador de eventos click e vincule a função desejada desta forma:

$(obj).unbind('click').bind('click', function(){... });
Matt Paxton
fonte
12

A solução óbvia é não ligar someMethod()duas vezes. Se você não pode consertar isso, você pode manter uma variável de estado para que ela só se vincule uma vez, assim:

function someMethod()
{
    if (!someMethod.bound) {
        $(obj).click(function() {});
        someMethod.bound = true;
    }
}

Observação: isso usa uma propriedade da própria função em vez de introduzir uma variável global para controlar se ela foi associada. Você também pode usar uma propriedade no próprio objeto.

Você pode ver como funciona aqui: http://jsfiddle.net/jfriend00/VHkxu/ .

jfriend00
fonte
11

Ou use a função one () do jQuery, que é semelhante a on (), mas só dispara o evento uma vez, mesmo se você ligá-lo várias vezes.

http://api.jquery.com/one/

xandrw
fonte
8
Às vezes ajuda. mas às vezes você quer a solução na qual possa: ANEXAR UMA VEZ, MAS USAR MUITOS.
Rzassar
5

O jQuery torna a chamada de alguma função possível apenas uma vez muito fácil:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}
Esailija
fonte
1
Isso só funcionará se someMethod for um método de um objeto ou função global.
jcubic
jQuery.nooptem apenas um caractere menor que function(){}, então é meio bobo dizer que está "ajudando" aqui, apenas fornecendo uma função vazia. Aqui está um exemplo não-jQuery e não-método desta solução geral:var fn = function(){ fn = function(){}; do stuff; };
1j01
1
@ 1j01 Editado para usar no $lugar
Esailija
2

Esta é uma sugestão, já que não conheço sua lógica. Pode ou não funcionar para você.

Tente combinar as funções jquery live () e one () para obter um resultado melhor do que as religações de eventos.

Os casos especiais funcionam quando você tem 2 elementos DOM (pai e filho). Live () no nó pai certifica-se de que o evento será invocado e, em seguida, chama one () para registrar dinamicamente o evento que seria executado apenas uma vez. (isso fornece funcionalidade semelhante, como religações).

Bambu
fonte
One()função funcionou em, chromemas não funcionou safariem Mac.
Half Blood Prince
2

Você pode adicionar classe css aos elementos vinculados e, em seguida, filtrá-los:

function someMethod()
{
    $(obj).not('.click-binded')
          .click(function {})
          .addClass('click-binded');
}

Este método também pode ser usado para plug-ins:

  $(obj).not('.datetimepicker-applied')
        .datetimepicker()
        .addClass('datetimepicker-applied');
Bakyt Abdrasulov
fonte
1
var bound = false;

function someMethod()
{
    if(!bound)
    {
       $(obj).click(function {});
       bound = true;
    }
}

mas eu provavelmente investigaria por que ele está sendo chamado duas vezes antes de fazer algum tipo de solução alternativa.

Kai Qing
fonte
3
Se você está indo dessa forma, considere a solução de jfriend00 where boundis attach to ao someMethod()invés de poluir o namespace global.
nuala
1

Se você deseja vincular ao objeto apenas uma vez, deve implementar um sinalizador e se ater a esse objeto.

Por exemplo:

if($('#id') && $('#id').data('done') == null)) {
    $('#id').bind('click', function() {
        alert('hello');
    });

    $('#id').data('done', true);
}
cscan
fonte
1

Você pode usar esta função de extensão jQuery.

$.fn.once = function (type, fn, uid) {
  if(uid == undefined) {
    console.error("Called $.once without uid\n", this, "\n", fn);
  }

  var dataStr = type+"-handler-"+uid;
  if(!this.data(dataStr)) {
    this.data(dataStr, true);
    this.on(type, fn);
  }
};

Em vez de fazer isso

$("button").on("click", function(){
  alert("You Clicked On A Button");
});

Você faz isso

$("button").once("click", function(){
  alert("You Clicked On A Button");
}, "btnHandler");

Agora, quando tenho uma função em torno disso

function addBtnHandler() {
  $("button").once("click", function() {
    alert("You Clicked On A Button");
  }, "btnHandler");
}

E eu chamo isso várias vezes

addBtnHandler();
addBtnHandler();
addBtnHandler();

Só faz isso uma vez.

Observe que a extensão funciona verificando uid e type. Isso significa que você pode ligar diferentes tipos de manipuladores com o mesmo uid, você pode ou não querer isso. Para alterá-lo, edite.

var dataStr = type+"-handler-"+uid;

Com algo como

var dataStr = "handler-"+uid;

Nathnolt
fonte
1

Eu também estava tentando usar o método off e on de jquery para vincular evento apenas uma vez com o elemento dom que ainda não existe ou o elemento dom ainda não foi criado.

$('.select').off('event').on('event', 'selector', function(e){ // });

Este código não estava funcionando corretamente

Eu descobri um método muito lucrativo que é 'um' método. É muito útil quando você deseja vincular um evento apenas uma vez.

Você pode encontrar o documento aqui http://api.jquery.com/one/

É o mesmo que o método 'ligado', mas é diferente com seu comportamento de não se manter no evento para seletores múltiplos.

$('body').one('click', 'selector', function(){ // do your stuff here });
Ankit Vishwakarma
fonte
1

Você pode conseguir isso com JS puro, usando o método addEventListener e sua opção uma vez

target.addEventListener('click', handler, {once: true});
Skav
fonte
2
Isso faz com que o evento se torne desvinculado depois que o elemento for clicado uma vez. Isso não resolve o problema de os eventos serem vinculados várias vezes.
Top Cat de