Acara khusus di jQuery?

180

Saya mencari beberapa masukan tentang cara mengimplementasikan penanganan acara kustom di jquery dengan cara terbaik. Saya tahu cara menghubungkan acara dari elemen dom seperti 'klik' dll, tapi saya sedang membangun perpustakaan javascript kecil / plugin untuk menangani beberapa fungsi pratinjau.

Saya menjalankan skrip untuk memperbarui beberapa teks dalam elemen dom dari serangkaian aturan dan input data / pengguna yang saya dapatkan, tetapi sekarang saya membutuhkan teks yang sama yang ditampilkan dalam elemen lain yang tidak mungkin diketahui oleh skrip ini. Yang saya butuhkan adalah pola yang baik untuk mengamati naskah ini menghasilkan teks yang dibutuhkan.

Jadi bagaimana saya melakukan ini? Apakah saya mengabaikan beberapa fungsi bawaan dalam jquery untuk meningkatkan / menangani acara pengguna atau apakah saya memerlukan beberapa plugin jquery untuk melakukannya? Menurut Anda apa cara / plugin terbaik untuk menangani ini?

Per Hornshøj-Schierbeck
sumber
3
Ada kerangka kerja lain, knockoutjs.com yang benar-benar dapat menyelesaikan masalah lama saya, jika ada yang melihat pertanyaan ini membutuhkannya.
Per Hornshøj-Schierbeck
2
Melihat saya terus mendapatkan reputasi dari pertanyaan ini, orang pasti masih membacanya. Saya hanya ingin memperbarui pilihan saya saat ini kerangka kerja sisi klien: angularjs.org
Per Hornshøj-Schierbeck
Meskipun sangat berbeda dari angular v1, Angular2 ( angular.io ) menunjukkan begitu banyak janji dan akan menjadi pilihan pertama saya setelah keluar dari beta / rc.
Per Hornshøj-Schierbeck

Jawaban:

105

Lihatlah ini:

(dicetak ulang dari halaman blog yang sudah kadaluwarsa http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ berdasarkan versi yang diarsipkan di http://web.archive.org/web /20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ )


Publikasikan / Berlangganan Dengan jQuery

17 Juni 2008

Dengan maksud untuk menulis UI jQuery yang terintegrasi dengan fungsionalitas offline Google Gears, saya telah mempermainkan beberapa kode untuk memilih status koneksi jaringan menggunakan jQuery.

Objek Deteksi Jaringan

Premis dasarnya sangat sederhana. Kami membuat instance objek deteksi jaringan yang akan melakukan polling URL secara berkala. Jika permintaan HTTP ini gagal, kita dapat mengasumsikan bahwa konektivitas jaringan telah hilang, atau server tidak dapat dijangkau pada saat ini.

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

Anda dapat melihat demo di sini. Atur browser Anda untuk bekerja offline dan lihat apa yang terjadi .... tidak, itu tidak terlalu menarik.

Pemicu dan Bind

Apa yang mengasyikkan (atau paling tidak apa yang mengasyikkan bagi saya) adalah metode yang digunakan untuk menyampaikan status melalui aplikasi. Saya telah menemukan metode yang sebagian besar tidak dibahas dalam mengimplementasikan sistem pub / sub menggunakan metode pemicu dan pengikatan jQuery.

Kode demo lebih tumpul daripada yang seharusnya. Objek deteksi jaringan menerbitkan acara 'status' ke dokumen yang secara aktif mendengarkannya dan kemudian menerbitkan acara 'beri tahu' ke semua pelanggan (lebih lanjut tentang hal itu nanti). Alasan di balik ini adalah bahwa dalam aplikasi dunia nyata mungkin akan ada beberapa logika yang mengontrol kapan dan bagaimana acara 'notifikasi' dipublikasikan.

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

Karena peristiwa pendekatan sentris DOM jQuery dipublikasikan ke (dipicu pada) elemen DOM. Ini bisa menjadi jendela atau objek dokumen untuk acara umum atau Anda bisa membuat objek jQuery menggunakan pemilih. Pendekatan yang saya ambil dengan demo adalah membuat pendekatan yang hampir sama dengan penempatan nama untuk mendefinisikan pelanggan.

Elemen DOM yang akan menjadi pelanggan digolongkan hanya dengan "pelanggan" dan "networkDetection". Kami kemudian dapat mempublikasikan acara hanya untuk elemen-elemen ini (yang hanya ada satu di demo) dengan memicu pemberitahuan acara$(“.subscriber.networkDetection”)

The #notifierdiv yang merupakan bagian dari .subscriber.networkDetectionkelompok pelanggan kemudian memiliki fungsi anonim terikat untuk itu, secara efektif bertindak sebagai pendengar.

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

Jadi, begitulah. Semuanya sangat verbose dan contoh saya sama sekali tidak menarik. Ini juga tidak menampilkan hal menarik yang dapat Anda lakukan dengan metode ini, tetapi jika ada yang tertarik untuk menggali sumbernya, silakan. Semua kode sebaris di bagian atas halaman demo

Vitor Silva
sumber
Sungguh apa yang saya cari. Dia mungkin benar bahwa itu adalah cara untuk pergi, tetapi saya tidak dapat berpikir jquery membutuhkan dukungan langsung atau plugin untuk menanganinya dengan lebih anggun. Saya akan menunggu sedikit dan melihat apakah ada masalah lain sebelum saya memberi tanda jawaban :)
Per Hornshøj-Schierbeck
6
Apakah ini kutipan dari suatu tempat? Jika ya, silakan kutip sumber Anda, dan berikan tautan, jika masih ada.
Aryeh Leib Taurog
1
Ya itu kutipan, di histori edit adalah tautan ini , saat ini tidak dapat diakses. Halaman yang diarsipkan ada di sini .
Stano
1
Ben Alman menulis sub-plugin jQuery pub mungil (mungil kecil) . Sangat elegan.
Barney
127

Tautan yang disediakan dalam jawaban yang diterima menunjukkan cara yang bagus untuk mengimplementasikan sistem pub / sub menggunakan jQuery, tetapi saya menemukan kode agak sulit dibaca, jadi di sini adalah versi kode saya yang disederhanakan:

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);
});
Manuel Navarro
sumber
10
Saya sangat suka jawaban ini. Siapa pun dapat membaca dokumen tentang trigger () bind () (dan on ()), tetapi jawaban ini memberikan contoh nyata untuk membuat event bus (pub / sub sistem) menggunakan jquery.
lostdorje
1
Bravo. Semua yang perlu saya ketahui.
Patrick Fisher
Saya telah menemukan bahwa jika Anda melewatkan array (dengan panjang> 1) ketika Anda memicu acara khusus, maka pendengar akan mendapatkan semua item array dalam argumen itu, sehingga Anda akan berakhir dengan nsejumlah argumen.
vsync
solusi untuk beberapa argumen yang menangani pendengar:var eventData = [].slice.call(arguments).splice(1)
vsync
2
Apakah ada cara untuk melakukan ini tanpa memiliki elemen dummy #notifier? Jika saya memiliki pustaka javascript dan menginginkan objek untuk mengekspos suatu peristiwa, saya tidak dapat memastikan elemen apa yang ada di halaman.
AaronLS
21

Saya kira begitu .. mungkin untuk 'mengikat' acara khusus, seperti (dari: 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" ]);
    });
Terikat
sumber
1
Saya mencari cara untuk meningkatkan suatu acara dan memiliki pemicu pelanggan / pendengar. Tidak memicunya secara manual karena objek yang naik tidak tahu siapa yang mendengarkan ...
Per Hornshøj-Schierbeck
2
Kode ini melakukan ini, bukan? myCustomEventdinaikkan, ikatan di atas menambahkan pendengar.
Sprintstar
15

Saya memiliki pertanyaan serupa, tetapi sebenarnya mencari jawaban yang berbeda; Saya ingin membuat acara khusus. Misalnya bukannya selalu mengatakan ini:

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

Saya ingin menyingkatnya menjadi ini:

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

memicu dan mengikat tidak menceritakan keseluruhan cerita - ini adalah plugin JQuery. http://docs.jquery.com/Plugins/Authoring

Fungsi "enterKey" dilampirkan sebagai properti ke jQuery.fn - ini adalah kode yang diperlukan:

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

Kelebihan dari hal di atas adalah Anda dapat menangani input keyboard dengan anggun di tautan pendengar seperti:

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

Suntingan: Diperbarui untuk meneruskan thiskonteks yang tepat ke penangan dengan benar, dan mengembalikan nilai pengembalian dari penangan ke jQuery (misalnya jika Anda ingin membatalkan acara dan menggelegak). Diperbarui untuk meneruskan objek acara jQuery yang tepat ke penangan, termasuk kode kunci dan kemampuan untuk membatalkan acara.

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

Chris Moschini
sumber
Chris - Fungsi ini bekerja dengan sempurna .. Satu-satunya hal yang tidak berfungsi adalah mengakses variabel ini .. saya dapat mengaksesnya menggunakan e.currentTarget .. tetapi bertanya-tanya apakah ada cara yang lebih efisien.
Addy
Bagus menangkap bug itu. Ya, jika Anda mengubah saluran 5 dari handler (ev); ke: handler.call (this, ev); maka argumen ini akan seperti biasanya dalam penangan event jquery standar. jsfiddle.net/b9chris/VwEb9
Chris Moschini
Apakah Anda juga tahu cara untuk menerapkan ini sebaliknya? Saya mencoba menggunakan contoh ini tetapi dengan scroll, yang tidak menyebar. Saya berpikir bahwa alih-alih menyuruh pendengar melakukan hardcode ke tubuh, saya membutuhkan elemen yang memiliki on—hampir terikat pada mereka untuk menembakkan peristiwa itu sendiri.
Gust van de Wal
Gust Saya tidak yakin dengan skenario yang Anda tanyakan; mungkin sebaiknya ditanyakan sebagai Pertanyaan dengan contoh kode?
Chris Moschini
9

Itu adalah posting lama, tetapi saya akan mencoba memperbaruinya dengan informasi baru.

Untuk menggunakan acara khusus, Anda harus mengikatnya ke beberapa elemen DOM dan untuk memicunya. Jadi, Anda perlu menggunakan

.on () metode mengambil jenis acara dan fungsi penanganan acara sebagai argumen. Secara opsional, ia juga dapat menerima data terkait peristiwa sebagai argumen kedua, mendorong fungsi penanganan peristiwa ke argumen ketiga. Setiap data yang diteruskan akan tersedia untuk fungsi penanganan acara di properti data objek acara. Fungsi penanganan acara selalu menerima objek acara sebagai argumen pertama.

dan

Metode .trigger () menggunakan tipe peristiwa sebagai argumennya. Secara opsional, ini juga dapat mengambil array nilai. Nilai-nilai ini akan diteruskan ke fungsi penanganan acara sebagai argumen setelah objek acara.

Kode ini terlihat seperti ini:

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

Penjelasan yang bagus dapat ditemukan di sini dan di sini . Kenapa ini bisa berguna? Saya menemukan cara menggunakannya dalam penjelasan yang sangat baik ini dari insinyur twitter .

PS Dalam javascript biasa Anda dapat melakukan ini dengan CustomEvent baru , tetapi waspadai masalah IE dan Safari.

Salvador Dali
sumber
3

Inilah cara saya membuat acara khusus:

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

Memang, Anda bisa melakukannya

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

Tetapi cara saya menulis memungkinkan Anda untuk mendeteksi apakah pengguna telah mencegah default atau tidak dengan melakukan

var prevented = event.isDefaultPrevented();

Ini memungkinkan Anda untuk mendengarkan permintaan pengguna akhir Anda untuk berhenti memproses acara tertentu, seperti jika Anda mengklik elemen tombol dalam formulir tetapi tidak ingin formulir untuk memposting jika ada kesalahan.


Saya kemudian biasanya mendengarkan acara seperti itu

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

Sekali lagi, Anda bisa melakukannya

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

Tapi saya selalu menemukan ini agak tidak aman, terutama jika Anda bekerja dalam tim.

Tidak ada yang salah dengan hal berikut:

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

Namun, asumsikan bahwa saya perlu melepaskan ikatan acara ini untuk alasan apa pun (bayangkan tombol yang dinonaktifkan). Maka saya harus melakukannya

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

Ini akan menghapus semua eventnameacara dari $(element). Anda tidak dapat mengetahui apakah seseorang di masa depan juga akan mengikat acara ke elemen itu, dan Anda juga akan secara tidak sengaja melepaskan ikatan acara tersebut.

Cara aman untuk menghindari ini adalah dengan namespace acara Anda dengan melakukan

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

Terakhir, Anda mungkin memperhatikan bahwa baris pertama adalah

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

Saya pribadi selalu membatalkan ikatan acara sebelum mengikatnya hanya untuk memastikan bahwa pengendali acara yang sama tidak pernah dipanggil berulang kali (bayangkan ini adalah tombol kirim pada formulir pembayaran dan acara telah terikat 5 kali)

Luke Madhanga
sumber
pendekatan yang bagus. +1 untuk namespace.
Aurovrata