Eventos personalizados em jQuery?


180

Estou procurando algumas informações sobre como implementar o tratamento de eventos personalizado no jquery da melhor maneira. Eu sei como conectar eventos dos elementos dom como 'click' etc, mas estou construindo uma pequena biblioteca / plugin javascript para lidar com algumas funcionalidades de visualização.

Eu tenho um script em execução para atualizar algum texto em um elemento dom a partir de um conjunto de regras e dados / entrada de usuário que obtive, mas agora preciso do mesmo texto mostrado em outros elementos que esse script não pode conhecer. O que eu preciso é de um bom padrão para observar de alguma forma esse script produzindo o texto necessário.

Então, como faço isso? Eu negligenciei algumas funcionalidades internas no jquery para aumentar / manipular eventos do usuário ou preciso de algum plugin jquery para fazer isso? Qual você acha que é a melhor maneira / plugin para lidar com isso?


3
Existe outra estrutura, o knockoutjs.com , que pode realmente resolver meu antigo problema, se alguém que estiver olhando para essa pergunta precisar.
Por Hornshøj-Schierbeck

2
Vendo que eu continuo obtendo reputação com essa pergunta, as pessoas ainda devem estar lendo. Eu só quero atualizar a minha escolha atual do framework MVC do lado do cliente: angularjs.org
Per Hornshøj-Schierbeck

Mesmo sendo completamente diferente do angular v1, o Angular2 ( angular.io ) mostra muita promessa e será a minha primeira escolha quando sair do beta / rc.
Por Hornshøj-Schierbeck

Respostas:


105

Dê uma olhada neste:

(reimpresso da página expirada do blog http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ com base na versão arquivada em http://web.archive.org/web /20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ )


Publicar / Assinar com jQuery

17 de junho de 2008

Com o objetivo de escrever uma interface do usuário do jQuery integrada à funcionalidade off-line do Google Gears, tenho usado algum código para pesquisar o status da conexão de rede usando o jQuery.

O objeto de detecção de rede

A premissa básica é muito simples. Criamos uma instância de um objeto de detecção de rede que pesquisará uma URL em intervalos regulares. Se essas solicitações HTTP falharem, podemos assumir que a conectividade da rede foi perdida ou o servidor está inacessível no momento.

$.networkDetection = function(url,interval){
    var url = url;
    var interval = interval;
    online = false;
    this.StartPolling = function(){
        this.StopPolling();
        this.timer = setInterval(poll, interval);
    };
    this.StopPolling = function(){
        clearInterval(this.timer);
    };
    this.setPollInterval= function(i) {
        interval = i;
    };
    this.getOnlineStatus = function(){
        return online;
    };
    function poll() {
        $.ajax({
            type: "POST",
            url: url,
            dataType: "text",
            error: function(){
                online = false;
                $(document).trigger('status.networkDetection',[false]);
            },
            success: function(){
                online = true;
                $(document).trigger('status.networkDetection',[true]);
            }
        });
    };
};

Você pode ver a demonstração aqui. Defina seu navegador para trabalhar offline e veja o que acontece…. não, não é muito emocionante.

Trigger and Bind

O que é empolgante (ou pelo menos o que me empolga) é o método pelo qual o status é retransmitido através do aplicativo. Eu me deparei com um método amplamente discutido de implementar um sistema pub / sub usando os métodos trigger e bind do jQuery.

O código de demonstração é mais obtuso do que precisa ser. O objeto de detecção de rede publica eventos de 'status' no documento que os escuta ativamente e, por sua vez, publica eventos de 'notificação' a ​​todos os assinantes (mais sobre os que serão posteriormente). O raciocínio por trás disso é que, em um aplicativo do mundo real, provavelmente haveria mais lógica controlando quando e como os eventos de 'notificação' são publicados.

$(document).bind("status.networkDetection", function(e, status){
    // subscribers can be namespaced with multiple classes
    subscribers = $('.subscriber.networkDetection');
    // publish notify.networkDetection even to subscribers
    subscribers.trigger("notify.networkDetection", [status])
    /*
    other logic based on network connectivity could go here
    use google gears offline storage etc
    maybe trigger some other events
    */
});

Devido à abordagem centrada no DOM, os eventos do jQuery são publicados para (acionados) elementos do DOM. Pode ser o objeto de janela ou documento para eventos gerais ou você pode gerar um objeto jQuery usando um seletor. A abordagem adotada na demonstração é criar uma abordagem quase espaçada para definir assinantes.

Os elementos DOM que devem ser assinantes são classificados simplesmente com "subscriber" e "networkDetection". Podemos publicar eventos apenas para esses elementos (dos quais existe apenas um na demonstração) acionando um evento de notificação em$(“.subscriber.networkDetection”)

A #notifierdiv que faz parte do .subscriber.networkDetectiongrupo de assinantes tem uma função anônima vinculada a ela, atuando efetivamente como ouvinte.

$('#notifier').bind("notify.networkDetection",function(e, online){
    // the following simply demonstrates
    notifier = $(this);
    if(online){
        if (!notifier.hasClass("online")){
            $(this)
                .addClass("online")
                .removeClass("offline")
                .text("ONLINE");
        }
    }else{
        if (!notifier.hasClass("offline")){
            $(this)
                .addClass("offline")
                .removeClass("online")
                .text("OFFLINE");
        }
    };
});

Então, lá vai você. É tudo bem detalhado e meu exemplo não é nada emocionante. Também não mostra nada de interessante que você possa fazer com esses métodos, mas se alguém estiver interessado em procurar na fonte, sinta-se à vontade. Todo o código está embutido no cabeçalho da página de demonstração


Exatamente o que eu estava procurando. Ele provavelmente está certo de que é o caminho a percorrer, mas não posso deixar de pensar que o jquery precisa de suporte direto ou de um plug-in para lidar com isso mais graciosamente. Vou esperar um pouco e ver se há outras
opiniões

6
Esta é uma citação de algum lugar? Em caso afirmativo, cite sua fonte e forneça um link, se ainda existir.
Aryeh Leib Taurog 03/03

1
Sim, é citação. No histórico de edições, este link é inacessível. A página arquivada está aqui .
Stano 5/07

1
Ben Alman escreveu um minúsculo (minúsculo minúsculo minúsculo) sub plugin de pub jQuery . É extremamente elegante.
Barney

127

O link fornecido na resposta aceita mostra uma boa maneira de implementar o sistema pub / sub usando jQuery, mas achei o código um pouco difícil de ler, então aqui está minha versão simplificada do código:

http://jsfiddle.net/tFw89/5/

$(document).on('testEvent', function(e, eventInfo) { 
  subscribers = $('.subscribers-testEvent');
  subscribers.trigger('testEventHandler', [eventInfo]);
});

$('#myButton').on('click', function() {
  $(document).trigger('testEvent', [1011]);
});

$('#notifier1').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier1)The value of eventInfo is: ' + eventInfo);
});

$('#notifier2').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier2)The value of eventInfo is: ' + eventInfo);
});

10
Eu realmente gosto desta resposta. Qualquer pessoa pode ler os documentos em trigger () bind () (e on ()), mas esta resposta fornece um exemplo concreto de criação de um barramento de eventos (sistema pub / subs) usando jquery.
lostdorje

1
Bravo. Tudo o que eu precisava saber.
Patrick Fisher

Descobri que, se você passar uma matriz (em que length> 1) ao disparar um evento personalizado, o ouvinte receberá todos os itens da matriz em seus argumentos; portanto, você terminará com um nnúmero de argumentos.
vsync 29/03

solução para a manipulação de múltiplos argumentos no ouvinte:var eventData = [].slice.call(arguments).splice(1)
vsync

2
Existe uma maneira de fazer isso sem ter os elementos fictícios #notifier? Se eu tinha uma biblioteca javascript e queria um objeto para expor um evento, não tenho certeza de quais elementos existem na página.
AaronLS

21

Eu acho que sim .. é possível 'ligar' eventos personalizados, como (de: http://docs.jquery.com/Events/bind#typedatafn ):

 $("p").bind("myCustomEvent", function(e, myName, myValue){
      $(this).text(myName + ", hi there!");
      $("span").stop().css("opacity", 1)
               .text("myName = " + myName)
               .fadeIn(30).fadeOut(1000);
    });
    $("button").click(function () {
      $("p").trigger("myCustomEvent", [ "John" ]);
    });

1
Estou procurando uma maneira de criar um evento e ter assinantes / ouvintes ativados nele. Não acioná-lo manualmente, pois o objeto levantado não sabe quem está ouvindo ...
Por Hornshøj-Schierbeck

2
Esse código faz isso, não é? myCustomEventé gerado, a ligação na parte superior adiciona um ouvinte.
Sprintstar

15

Eu tinha uma pergunta semelhante, mas estava realmente procurando uma resposta diferente; Estou procurando criar um evento personalizado. Por exemplo, em vez de sempre dizer isso:

$('#myInput').keydown(function(ev) {
    if (ev.which == 13) {
        ev.preventDefault();
        // Do some stuff that handles the enter key
    }
});

Quero abreviá-lo para isso:

$('#myInput').enterKey(function() {
    // Do some stuff that handles the enter key
});

trigger e bind não contam toda a história - este é um plugin JQuery. http://docs.jquery.com/Plugins/Authoring

A função "enterKey" é anexada como uma propriedade ao jQuery.fn - este é o código necessário:

(function($){
    $('body').on('keydown', 'input', function(ev) {
        if (ev.which == 13) {
            var enterEv = $.extend({}, ev, { type: 'enterKey' });
            return $(ev.target).trigger(enterEv);
        }
    });

    $.fn.enterKey = function(selector, data, fn) {
        return this.on('enterKey', selector, data, fn);
    };
})(jQuery);

http://jsfiddle.net/b9chris/CkvuJ/4/

Um dos detalhes acima é que você pode manipular a entrada do teclado normalmente em ouvintes de link, como:

$('a.button').on('click enterKey', function(ev) {
    ev.preventDefault();
    ...
});

Edições: atualizadas para passar adequadamente o thiscontexto correto para o manipulador e retornar qualquer valor de retorno do manipulador para o jQuery (por exemplo, no caso de você querer cancelar o evento e fazer bolhas). Atualizado para passar um objeto de evento jQuery adequado para os manipuladores, incluindo código de chave e capacidade de cancelar o evento.

Jsfiddle antigo: http://jsfiddle.net/b9chris/VwEb9/24/


Chris - A função funcionou perfeitamente .. a única coisa que não está funcionando é acessar essa variável .. eu posso acessá-la usando e.currentTarget .. mas fiquei imaginando se existe uma maneira mais eficiente.
Addy

Boa captura desse bug. Sim, se você alterar a linha 5 do manipulador (ev); para: handler.call (this, ev); então o argumento this será como normalmente é nos manipuladores de eventos jquery padrão. jsfiddle.net/b9chris/VwEb9 #
Chris Moschini

Você também conhece uma maneira de implementar isso de maneira inversa? Estou tentando usar este exemplo, mas com scroll, que não se propaga. Penso que, em vez de ter os ouvintes codificados no corpo, preciso dos elementos que têm o on-evento vinculado a eles para disparar o evento eles mesmos.
Gust van de Wal

Rajada, não tenho certeza do cenário que você está perguntando; pode ser perguntado como uma pergunta com amostra de código?
Chris Moschini

9

É um post antigo, mas tentarei atualizá-lo com novas informações.

Para usar eventos personalizados, é necessário vinculá-lo a algum elemento DOM e ativá-lo. Então você precisa usar

O método .on () usa um tipo de evento e uma função de manipulação de eventos como argumentos. Opcionalmente, ele também pode receber dados relacionados ao evento como seu segundo argumento, empurrando a função de manipulação de eventos para o terceiro argumento. Quaisquer dados passados ​​estarão disponíveis para a função de manipulação de eventos na propriedade de dados do objeto de evento. A função de manipulação de eventos sempre recebe o objeto de evento como seu primeiro argumento.

e

O método .trigger () usa um tipo de evento como argumento. Opcionalmente, ele também pode receber uma matriz de valores. Esses valores serão passados ​​para a função de manipulação de eventos como argumentos após o objeto de evento.

O código fica assim:

$(document).on("getMsg", {
    msg: "Hello to everyone",
    time: new Date()
}, function(e, param) {
    console.log( e.data.msg );
    console.log( e.data.time );
    console.log( param );
});

$( document ).trigger("getMsg", [ "Hello guys"] );

Uma boa explicação pode ser encontrada aqui e aqui . Por que exatamente isso pode ser útil? Eu descobri como usá-lo nesta excelente explicação do engenheiro do twitter .

PS Em javascript comum, você pode fazer isso com o novo CustomEvent , mas cuidado com os problemas do IE e do Safari.


3

Aqui está como eu crio eventos personalizados:

var event = jQuery.Event('customEventName');
$(element).trigger(event);

Concedido, você poderia simplesmente fazer

$(element).trigger('eventname');

Mas a maneira como escrevi permite detectar se o usuário impediu o padrão ou não fazendo

var prevented = event.isDefaultPrevented();

Isso permite que você ouça a solicitação do usuário final para interromper o processamento de um evento específico, como se você clicar em um elemento de botão em um formulário, mas não desejar que o formulário seja publicado se houver um erro.


Eu costumo ouvir eventos como esse

$(element).off('eventname.namespace').on('eventname.namespace', function () {
    ...
});

Mais uma vez, você poderia fazer

$(element).on('eventname', function () {
    ...
});

Mas sempre achei isso um tanto inseguro, principalmente se você estiver trabalhando em equipe.

Não há nada errado com o seguinte:

$(element).on('eventname', function () {});

No entanto, suponha que eu precise desvincular este evento por qualquer motivo (imagine um botão desativado). Então eu teria que fazer

$(element).off('eventname', function () {});

Isso removerá todos os eventnameeventos de $(element). Você não pode saber se alguém no futuro também vinculará um evento a esse elemento e, inadvertidamente, também desvinculará esse evento.

A maneira segura de evitar isso é colocar um namespace em seus eventos, fazendo

$(element).on('eventname.namespace', function () {});

Por fim, você deve ter notado que a primeira linha foi

$(element).off('eventname.namespace').on('eventname.namespace', ...)

Eu pessoalmente sempre unbind um evento antes obrigatório apenas para se certificar de que o mesmo manipulador de eventos nunca é chamado várias vezes (imagine esse foi o botão enviar em um formulário de pagamento e o evento tinha sido obrigado 5 vezes)


boa abordagem. +1 para espaço para nome.
Aurovrata 8/05/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.