Eventi personalizzati in jQuery?


180

Sto cercando alcuni suggerimenti su come implementare la gestione personalizzata degli eventi in jquery nel modo migliore. So come collegare eventi dagli elementi dom come 'click' ecc., Ma sto costruendo una piccola libreria / plugin javascript per gestire alcune funzionalità di anteprima.

Ho uno script in esecuzione per aggiornare un po 'di testo in un elemento dom da una serie di regole e input di dati / utente che ho ottenuto, ma ora ho bisogno dello stesso testo mostrato in altri elementi che questo script non può conoscere. Ciò di cui ho bisogno è un buon modello per osservare in qualche modo questa sceneggiatura che produce il testo necessario.

Quindi come posso farlo? Ho trascurato alcune funzionalità integrate in jquery per sollevare / gestire eventi utente o ho bisogno di alcuni plugin jquery per farlo? Quale pensi sia il modo / plug-in migliore per gestirlo?


3
Esiste un altro framework, knockoutjs.com che può effettivamente risolvere il mio vecchio problema, se qualcuno che ha bisogno di questa domanda ne ha bisogno.
Per Hornshøj-Schierbeck l'

2
Visto che continuo a ottenere reputazione da questa domanda, la gente deve ancora leggerlo. Voglio solo aggiornare la mia attuale scelta di framework mvc lato client: angularjs.org
Per Hornshøj-Schierbeck il

Anche se è completamente diverso da angular v1, Angular2 ( angular.io ) mostra così tante promesse e sarà la mia prima scelta una volta fuori dalla beta / rc.
Per Hornshøj-Schierbeck,

Risposte:


105

Guarda questo:

(ristampato dalla pagina del blog scaduta http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ in base alla versione archiviata su http://web.archive.org/web /20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ )


Pubblica / Iscriviti con jQuery

17 giugno 2008

Al fine di scrivere un'interfaccia utente jQuery integrata con la funzionalità offline di Google Gears, ho giocato con un po 'di codice per sondare lo stato della connessione di rete usando jQuery.

L'oggetto di rilevamento della rete

La premessa di base è molto semplice. Creiamo un'istanza di un oggetto di rilevamento della rete che eseguirà il polling di un URL a intervalli regolari. Se queste richieste HTTP falliscono, possiamo supporre che la connettività di rete sia andata persa o che al momento il server non sia semplicemente raggiungibile.

$.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]);
            }
        });
    };
};

Puoi vedere la demo qui. Imposta il tuo browser in modo che funzioni offline e vedi cosa succede ... no, non è molto eccitante.

Trigger and Bind

Ciò che è eccitante (o almeno ciò che mi eccita) è il metodo con cui lo stato viene trasmesso attraverso l'applicazione. Mi sono imbattuto in un metodo ampiamente discusso di implementazione di un pub / sottosistema usando i metodi trigger e bind di jQuery.

Il codice demo è più ottuso di quanto debba essere. L'oggetto di rilevamento della rete pubblica eventi di "stato" nel documento che li ascolta attivamente e, a sua volta, pubblica eventi di "notifica" a tutti gli abbonati (ne parleremo più avanti). Il ragionamento alla base di ciò è che in un'applicazione del mondo reale ci sarebbe probabilmente qualche logica in più che controlla quando e come vengono pubblicati gli eventi di "notifica".

$(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
    */
});

A causa dell'approccio incentrato sul DOM di jQuery, gli eventi vengono pubblicati su (attivati) elementi DOM. Può essere l'oggetto finestra o documento per eventi generali oppure è possibile generare un oggetto jQuery utilizzando un selettore. L'approccio che ho adottato con la demo è quello di creare un approccio quasi spaziale alla definizione degli abbonati.

Gli elementi DOM che devono essere abbonati vengono classificati semplicemente con "abbonato" e "networkDetection". Possiamo quindi pubblicare eventi solo su questi elementi (di cui ce n'è solo uno nella demo) attivando un evento di notifica$(“.subscriber.networkDetection”)

Il #notifierdiv che fa parte del .subscriber.networkDetectiongruppo di abbonati ha quindi una funzione anonima ad esso associata, che agisce efficacemente come ascoltatore.

$('#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");
        }
    };
});

Quindi, eccoti. È tutto piuttosto prolisso e il mio esempio non è affatto eccitante. Inoltre, non mostra nulla di interessante che potresti fare con questi metodi, ma se qualcuno è interessato a scavare nella fonte sentiti libero. Tutto il codice è in linea nella testa della pagina demo


Esattamente quello che stavo cercando. Probabilmente ha ragione che è la strada da percorrere, ma non posso fare a meno di pensare che jquery abbia bisogno del supporto diretto o di un plugin per gestirlo con più grazia. Aspetterò un po 'e vedrò se ci sono altri punti sul problema prima che io
segnali

6
È una citazione da qualche parte? In tal caso, cita la tua fonte e fornisci un link, se esiste ancora.
Aryeh Leib Taurog

1
Sì, è una citazione, nella cronologia delle modifiche è presente questo link , attualmente non è accessibile. La pagina archiviata è qui .
Stano,

1
Ben Alman ha scritto un piccolo plug-in per pub jQuery . È estremamente elegante.
Barney,

127

Il link fornito nella risposta accettata mostra un buon modo per implementare il pub / sottosistema usando jQuery, ma ho trovato il codice un po 'difficile da leggere, quindi ecco la mia versione semplificata del codice:

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
Mi piace molto questa risposta. Chiunque può leggere i documenti su trigger () bind () (e su ()), ma questa risposta fornisce un esempio concreto di creazione di un bus eventi (pub / sottosistema) usando jquery.
lostdorje,

1
Bravo. Tutto quello che dovevo sapere.
Patrick Fisher,

Ho scoperto che se passi un array (dove lunghezza> 1) quando attivi un evento personalizzato, allora l'ascoltatore otterrà tutti gli elementi dell'array nei suoi argomenti, quindi finirai con il nnumero di argomenti.
vsync,

soluzione alla gestione di più argomenti nel listener:var eventData = [].slice.call(arguments).splice(1)
vsync

2
C'è un modo per farlo senza avere gli elementi fittizi #notifier? Se avessi una libreria javascript e volessi che un oggetto esponesse un evento, non posso essere sicuro di quali elementi esistano nella pagina.
AaronLS,

21

Penso di sì ... è possibile "associare" eventi personalizzati, come (da: 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
Sto cercando un modo per creare un evento e fare in modo che abbonati / ascoltatori si attivino. Non attivarlo manualmente poiché l'oggetto che solleva non sa chi sta ascoltando ...
Per Hornshøj-Schierbeck il

2
Questo codice fa questo, vero? myCustomEventviene sollevato, il legame in alto aggiunge un ascoltatore.
Sprintstar,

15

Avevo una domanda simile, ma in realtà cercavo una risposta diversa; Sto cercando di creare un evento personalizzato. Ad esempio invece di dire sempre questo:

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

Voglio abbreviarlo a questo:

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

trigger e bind non raccontano l'intera storia - questo è un plug-in JQuery. http://docs.jquery.com/Plugins/Authoring

La funzione "enterKey" viene collegata come proprietà a jQuery.fn - questo è il codice richiesto:

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

Una buona parte di quanto sopra è che puoi gestire con grazia l'input da tastiera su listener di link come:

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

Modifiche: aggiornato per passare correttamente il giusto thiscontesto al gestore e per restituire qualsiasi valore di ritorno dal gestore a jQuery (ad esempio nel caso in cui si stesse cercando di annullare l'evento e il bubbling). Aggiornato per trasmettere ai gestori un oggetto evento jQuery appropriato, incluso il codice chiave e la possibilità di annullare l'evento.

Vecchio jsfiddle: http://jsfiddle.net/b9chris/VwEb9/24/


Chris - La funzione ha funzionato perfettamente .. l'unica cosa che non funziona è l'accesso a questa variabile .. Sono in grado di accedervi usando e.currentTarget .. ma mi chiedevo se esiste un modo più efficiente.
Addy

Buona cattura di quel bug. Sì, se si cambia la riga 5 dal gestore (ev); a: handler.call (this, ev); allora l'argomento this sarà come è normalmente nei gestori di eventi jquery standard. jsfiddle.net/b9chris/VwEb9
Chris Moschini

Conosci anche un modo per implementarlo al contrario? Sto cercando di usare questo esempio ma con scroll, che non si propaga. Penso che invece di avere gli ascoltatori hardcoded sul corpo, ho bisogno degli elementi che hanno l' onevento legato a loro per innescare l'evento stesso.
Gust van de Wal,

Non sono sicuro dello scenario di cui stai chiedendo; potrebbe essere meglio fare una domanda con esempio di codice?
Chris Moschini,

9

È un vecchio post, ma proverò ad aggiornarlo con una nuova informazione.

Per utilizzare eventi personalizzati è necessario associarlo a qualche elemento DOM e attivarlo. Quindi devi usare

Il metodo .on () accetta un tipo di evento e una funzione di gestione degli eventi come argomenti. Facoltativamente, può anche ricevere dati relativi agli eventi come secondo argomento, spingendo la funzione di gestione degli eventi al terzo argomento. Tutti i dati passati saranno disponibili per la funzione di gestione degli eventi nella proprietà data dell'oggetto evento. La funzione di gestione degli eventi riceve sempre l'oggetto evento come primo argomento.

e

Il metodo .trigger () accetta un tipo di evento come argomento. Facoltativamente, può anche richiedere una matrice di valori. Questi valori verranno passati alla funzione di gestione degli eventi come argomenti dopo l'oggetto evento.

Il codice è simile al seguente:

$(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"] );

Una bella spiegazione può essere trovata qui e qui . Perché esattamente questo può essere utile? Ho scoperto come usarlo in questa eccellente spiegazione dell'ingegnere di Twitter .

PS In javascript semplice puoi farlo con il nuovo CustomEvent , ma fai attenzione ai problemi di IE e Safari.


3

Ecco come autore eventi personalizzati:

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

Certo, potresti semplicemente farlo

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

Ma il modo in cui ho scritto ti consente di rilevare se l'utente ha impedito il default o meno

var prevented = event.isDefaultPrevented();

Ciò consente di ascoltare la richiesta dell'utente finale di interrompere l'elaborazione di un determinato evento, ad esempio se si fa clic su un elemento pulsante in un modulo ma non si desidera che il modulo pubblichi in caso di errore.


Di solito ascolto quindi eventi del genere

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

Ancora una volta, potresti semplicemente fare

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

Ma l'ho sempre trovato un po 'pericoloso, specialmente se lavori in gruppo.

Non c'è nulla di sbagliato in quanto segue:

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

Tuttavia, supponiamo che sia necessario separare questo evento per qualsiasi motivo (immagina un pulsante disabilitato). Dovrei quindi fare

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

Questo rimuoverà tutti gli eventnameeventi da $(element). Non puoi sapere se qualcuno in futuro vincolerà anche un evento a quell'elemento e anche tu inavvertitamente non vincolerai quell'evento

Il modo sicuro per evitarlo è quello di spaziare i tuoi eventi facendo

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

Infine, potresti aver notato che la prima riga era

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

Io personalmente sempre unbind un evento prima vincolante solo per fare in modo che lo stesso gestore di eventi non viene mai chiamato più volte (immaginate questo è stato il pulsante di invio su un modulo di pagamento e l'evento era stato legato per 5 volte)


bel approccio. +1 per lo spazio dei nomi.
Aurovrata
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.