เหตุการณ์ที่กำหนดเองใน jQuery?


180

ฉันกำลังมองหาข้อมูลบางอย่างเกี่ยวกับวิธีการใช้การจัดการเหตุการณ์ที่กำหนดเองใน jquery วิธีที่ดีที่สุด ฉันรู้วิธีเชื่อมต่อเหตุการณ์จากองค์ประกอบ dom เช่น 'คลิก' ฯลฯ แต่ฉันกำลังสร้างไลบรารี / ปลั๊กอินจาวาสคริปต์เล็ก ๆ เพื่อจัดการกับฟังก์ชันการแสดงตัวอย่าง

ฉันได้รับสคริปต์ทำงานเพื่ออัปเดตข้อความบางส่วนในองค์ประกอบ dom จากชุดของกฎและการป้อนข้อมูล / ผู้ใช้ที่ฉันได้รับ แต่ตอนนี้ฉันต้องการข้อความเดียวกันที่แสดงในองค์ประกอบอื่น ๆ ที่สคริปต์นี้ไม่สามารถรู้ได้ สิ่งที่ฉันต้องการก็คือรูปแบบที่ดีในการสังเกตสคริปต์นี้ที่สร้างข้อความที่ต้องการ

ดังนั้นฉันจะทำอย่างไร ฉันมองข้ามฟังก์ชั่นบิวอินใน jquery เพื่อยกระดับ / จัดการกิจกรรมของผู้ใช้หรือฉันต้องการปลั๊กอิน jquery เพื่อทำมันหรือไม่? คุณคิดว่าอะไรเป็นวิธีที่ดีที่สุดในการจัดการปลั๊กอินนี้?


3
มีอีกกรอบหนึ่งคือknockoutjs.comที่สามารถแก้ปัญหาเดิมของฉันได้ถ้าใครก็ตามที่ดูคำถามนี้ต้องการมัน
ต่อHornshøj-Schierbeck

2
เมื่อฉันได้รับชื่อเสียงจากคำถามนี้ต่อไปผู้คนยังคงต้องอ่านมันต่อไป ฉันต้องการอัปเดตตัวเลือกปัจจุบันของฉันสำหรับกรอบ mvc ฝั่งไคลเอ็นต์: angularjs.org
ต่อHornshøj-Schierbeck

แม้ว่ามันจะแตกต่างอย่างสิ้นเชิงจาก angular v1, Angular2 ( angular.io ) แสดงคำสัญญามากมายและจะเป็นตัวเลือกแรกของฉันเมื่อมันออกมาจากเบต้า / rc
ต่อHornshøj-Schierbeck

คำตอบ:


105

ดูที่นี้:

(พิมพ์ซ้ำจากหน้าบล็อกที่หมดอายุhttp://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ตามเวอร์ชั่นที่เก็บถาวรไว้ที่http://web.archive.org/web /20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ )


เผยแพร่ / สมัครสมาชิกด้วย jQuery

17 มิถุนายน 2551

ด้วยมุมมองในการเขียน jQuery UI ที่รวมเข้ากับฟังก์ชั่นออฟไลน์ของ Google Gears ฉันได้เล่นกับโค้ดบางอย่างเพื่อสำรวจสถานะการเชื่อมต่อเครือข่ายโดยใช้ jQuery

วัตถุตรวจจับเครือข่าย

หลักฐานพื้นฐานง่ายมาก เราสร้างตัวอย่างของวัตถุตรวจจับเครือข่ายซึ่งจะสำรวจ URL ในช่วงเวลาปกติ หากคำขอ HTTP เหล่านี้ล้มเหลวเราสามารถสันนิษฐานได้ว่าการเชื่อมต่อเครือข่ายขาดหายไปหรือเซิร์ฟเวอร์ไม่สามารถเข้าถึงได้ในเวลาปัจจุบัน

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

คุณสามารถดูตัวอย่างได้ที่นี่ ตั้งค่าเบราว์เซอร์ของคุณให้ทำงานแบบออฟไลน์และดูว่าเกิดอะไรขึ้น…. ไม่มันไม่น่าตื่นเต้นมาก

ทริกเกอร์และการผูก

สิ่งที่น่าตื่นเต้น (หรืออย่างน้อยสิ่งที่ทำให้ฉันตื่นเต้น) เป็นวิธีการที่สถานะได้รับการถ่ายทอดผ่านแอปพลิเคชัน ฉันสะดุดกับวิธีการที่ไม่ได้กล่าวถึงมากในการนำระบบ pub / sub มาใช้โดยใช้วิธีการทริกเกอร์และการเชื่อมของ jQuery

โค้ดตัวอย่างนั้นมีความป้านมากกว่าที่ควรจะเป็น วัตถุตรวจจับเครือข่ายเผยแพร่เหตุการณ์ 'สถานะ' ไปยังเอกสารที่รับฟังพวกเขาอย่างแข็งขันและจะเผยแพร่กิจกรรม 'แจ้งเตือน' ให้กับสมาชิกทั้งหมด (เพิ่มเติมในภายหลัง) เหตุผลที่อยู่เบื้องหลังนี้คือในแอปพลิเคชันในโลกแห่งความเป็นจริงมันอาจจะมีเหตุผลมากกว่านี้ในการควบคุมเวลาและวิธีการเผยแพร่ 'แจ้งเตือน' เหตุการณ์

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

เนื่องจากมีการเผยแพร่กิจกรรมวิธีการศูนย์กลาง DOM ของ jQuery ให้กับองค์ประกอบ DOM (เรียกใช้) นี่อาจเป็นหน้าต่างหรือวัตถุเอกสารสำหรับเหตุการณ์ทั่วไปหรือคุณสามารถสร้างวัตถุ jQuery โดยใช้ตัวเลือก วิธีที่ฉันใช้กับการสาธิตคือการสร้างวิธีการกำหนดชื่อแบบเกือบเพื่อกำหนดสมาชิก

องค์ประกอบ DOM ที่จะเป็นสมาชิกจะถูกจัดประเภทอย่างง่าย ๆ ด้วย "สมาชิก" และ "networkDetection" จากนั้นเราสามารถเผยแพร่กิจกรรมไปยังองค์ประกอบเหล่านี้เท่านั้น (ซึ่งมีเพียงหนึ่งเหตุการณ์ในการสาธิต) โดยการเปิดใช้งานกิจกรรมการแจ้งเตือน$(“.subscriber.networkDetection”)

#notifierdiv ซึ่งเป็นส่วนหนึ่งของ.subscriber.networkDetectionกลุ่มสมาชิกแล้วมีฟังก์ชั่นที่ไม่ระบุชื่อที่ถูกผูกไว้กับมันได้อย่างมีประสิทธิภาพทำหน้าที่เป็นผู้ฟัง

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

ดังนั้นคุณไป มันเป็นสิ่งที่สวยงามและตัวอย่างของฉันไม่ได้น่าตื่นเต้นเลย มันยังไม่แสดงสิ่งที่น่าสนใจที่คุณสามารถทำได้ด้วยวิธีการเหล่านี้ แต่ถ้าใครที่สนใจที่จะขุดผ่านแหล่งที่มารู้สึกฟรี รหัสทั้งหมดเป็นแบบอินไลน์ในส่วนหัวของหน้าตัวอย่าง


สิ่งที่ฉันกำลังมองหา เขาอาจพูดถูกว่าเป็นวิธีไป แต่ฉันอดคิดไม่ได้ว่า jquery ต้องการการสนับสนุนโดยตรงหรือปลั๊กอินเพื่อจัดการกับมันอย่างสง่างาม ฉันจะรอสักครู่และดูว่ามีคนอื่น ๆ จะใช้เวลาในปัญหาที่เกิดขึ้นก่อนที่ผมจะติดธงคำตอบ :)
ต่อHornshøj-Schierbeck

6
นี่เป็นคำพูดจากที่อื่นหรือไม่? ถ้าเป็นเช่นนั้นโปรดอ้างอิงแหล่งที่มาของคุณและระบุลิงก์หากยังมีอยู่
Aryeh Leib Taurog

1
ใช่มันเป็นคำพูดในประวัติการแก้ไขคือลิงค์นี้ในขณะนี้มันไม่สามารถเข้าถึงได้ หน้าที่จัดเก็บอยู่ที่นี่
Stano

1
เบน Almanเขียนเล็ก ๆ (เล็กเล็กเล็ก) ปลั๊กอิน jQuery ย่อยผับ มันสวยงามมาก
บาร์นีย์

127

ลิงก์ที่ให้ไว้ในคำตอบที่ยอมรับนั้นเป็นวิธีที่ดีในการติดตั้งระบบpub / subโดยใช้ jQuery แต่ฉันพบว่ารหัสอ่านค่อนข้างยากดังนั้นนี่เป็นเวอร์ชั่นที่เรียบง่ายของรหัส

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
ฉันชอบคำตอบนี้จริงๆ ทุกคนสามารถอ่าน docs ในทริกเกอร์ () ผูก () (และบน ()) แต่คำตอบนี้ให้ตัวอย่างที่เป็นรูปธรรมของการสร้าง Event Bus (pub / sub system) โดยใช้ jquery
lostdorje

1
ไชโย ทุกสิ่งที่ฉันต้องการรู้
แพทริคฟิชเชอร์

ฉันได้พบว่าหากคุณผ่านอาร์เรย์ (ที่ความยาว> 1) เมื่อคุณทริกเกอร์เหตุการณ์ที่กำหนดเองผู้ฟังจะได้รับรายการอาร์เรย์ทั้งหมดในอาร์กิวเมนต์มันดังนั้นคุณจะจบลงด้วยnจำนวนอาร์กิวเมนต์
vsync

วิธีการแก้ปัญหาข้อโต้แย้งหลายประการในผู้ฟัง:var eventData = [].slice.call(arguments).splice(1)
vsync

2
มีวิธีการทำเช่นนี้โดยไม่ต้องมีองค์ประกอบ #notifier dummy หรือไม่ หากฉันมีไลบรารี javascript และต้องการให้วัตถุแสดงเหตุการณ์ฉันไม่สามารถแน่ใจได้ว่ามีองค์ประกอบใดบ้างในหน้า
AaronLS

21

ฉันคิดว่า .. เป็นไปได้ที่จะผูกเหตุการณ์ที่กำหนดเองเช่น (จาก: 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
ฉันกำลังมองหาวิธีเพิ่มกิจกรรมและให้สมาชิก / ผู้ฟังทริกเกอร์ ไม่เรียกใช้ด้วยตนเองเนื่องจากวัตถุที่เลี้ยงไม่ทราบว่าใครกำลังฟังอยู่ ...
ต่อHornshøj-Schierbeck

2
รหัสนี้ทำสิ่งนี้ใช่ไหม myCustomEventถูกเพิ่มการเชื่อมที่ด้านบนจะเพิ่มผู้ฟัง
Sprintstar

15

ฉันมีคำถามที่คล้ายกัน แต่จริงๆแล้วกำลังมองหาคำตอบที่แตกต่างกัน; ฉันต้องการสร้างกิจกรรมที่กำหนดเอง ตัวอย่างเช่นแทนที่จะพูดสิ่งนี้เสมอ:

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

ฉันต้องการย่อมัน:

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

ทริกเกอร์และการผูกไม่ได้บอกเรื่องราวทั้งหมด - นี่คือปลั๊กอิน JQuery http://docs.jquery.com/Plugins/Authoring

ฟังก์ชัน "enterKey" ได้รับการเชื่อมต่อเป็นคุณสมบัติของ jQuery.fn - นี่คือรหัสที่ต้องการ:

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

สิ่งที่เหนือกว่าคือคุณสามารถจัดการกับคีย์บอร์ดที่มีต่อผู้ฟังลิงค์เช่น:

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

การแก้ไข: อัปเดตเพื่อส่งthisบริบทที่ถูกต้องไปยังตัวจัดการอย่างถูกต้องและส่งคืนค่าส่งคืนใด ๆ จากตัวจัดการไปยัง jQuery (ตัวอย่างเช่นในกรณีที่คุณต้องการยกเลิกกิจกรรมและเดือดปุด ๆ ) อัปเดตเพื่อส่งวัตถุเหตุการณ์ jQuery ที่เหมาะสมไปยังตัวจัดการรวมถึงรหัสคีย์และความสามารถในการยกเลิกเหตุการณ์

jsfiddle เก่า: http://jsfiddle.net/b9chris/VwEb9/24/


Chris - ฟังก์ชั่นทำงานได้อย่างสมบูรณ์แบบ .. สิ่งเดียวที่ไม่ทำงานคือการเข้าถึงตัวแปรนี้ .. ฉันสามารถเข้าถึงได้โดยใช้ e.currentTarget .. แต่ก็สงสัยว่ามีวิธีที่มีประสิทธิภาพมากกว่านี้ไหม
Addy

จับข้อผิดพลาดได้ดี ใช่ถ้าคุณเปลี่ยนบรรทัด 5 จากตัวจัดการ (ev); ถึง: handler.call (สิ่งนี้, ev); ดังนั้นอาร์กิวเมนต์นี้จะเป็นตามปกติในตัวจัดการเหตุการณ์ jquery มาตรฐาน jsfiddle.net/b9chris/VwEb9
Chris Moschini

คุณรู้วิธีที่จะใช้วิธีนี้ในอีกทางหนึ่งหรือไม่? ฉันพยายามใช้ตัวอย่างนี้ แต่ใช้scrollซึ่งไม่เผยแพร่ ฉันคิดว่าแทนที่จะให้ผู้ฟังถูก hardcoded ต่อร่างกายฉันต้องการองค์ประกอบที่มีonเหตุการณ์ที่ผูกไว้กับพวกเขาเพื่อยิงเหตุการณ์ด้วยตัวเอง
Gust van de Wal

ฉันไม่แน่ใจในสถานการณ์ที่คุณถาม อาจถูกถามว่าเป็นคำถามที่ดีที่สุดพร้อมตัวอย่างรหัสหรือไม่
Chris Moschini

9

มันเป็นโพสต์เก่า แต่ฉันจะพยายามอัปเดตด้วยข้อมูลใหม่

ในการใช้เหตุการณ์ที่กำหนดเองคุณต้องผูกมันกับองค์ประกอบ DOM บางอย่างและเพื่อทริกเกอร์มัน ดังนั้นคุณต้องใช้

.on () วิธีการใช้ประเภทเหตุการณ์และฟังก์ชั่นการจัดการเหตุการณ์เป็นข้อโต้แย้ง นอกจากนี้ยังสามารถรับข้อมูลที่เกี่ยวข้องกับเหตุการณ์เป็นอาร์กิวเมนต์ที่สองได้โดยกดฟังก์ชันการจัดการเหตุการณ์ไปยังอาร์กิวเมนต์ที่สาม ข้อมูลใด ๆ ที่ส่งผ่านจะพร้อมใช้งานสำหรับฟังก์ชันการจัดการเหตุการณ์ในคุณสมบัติข้อมูลของวัตถุเหตุการณ์ ฟังก์ชันการจัดการเหตุการณ์ได้รับวัตถุเหตุการณ์เป็นอาร์กิวเมนต์แรกเสมอ

และ

.trigger () วิธีการใช้ประเภทเหตุการณ์เป็นอาร์กิวเมนต์ อีกทางเลือกหนึ่งก็สามารถใช้อาร์เรย์ของค่า ค่าเหล่านี้จะถูกส่งผ่านไปยังฟังก์ชันการจัดการเหตุการณ์เป็นอาร์กิวเมนต์หลังจากวัตถุเหตุการณ์

รหัสมีลักษณะดังนี้:

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

คำอธิบายที่ดีสามารถพบได้ที่นี่และที่นี่ ทำไมสิ่งนี้ถึงมีประโยชน์ ผมพบว่าวิธีการใช้งานที่ดีเยี่ยมในการอธิบายนี้จากวิศวกรทวิตเตอร์

PSในจาวาสคริปต์ธรรมดาคุณสามารถทำได้ด้วยCustomEvent ใหม่แต่ระวังปัญหา IE และ Safari


3

นี่คือวิธีที่ฉันเขียนเหตุการณ์ที่กำหนดเอง:

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

จริงอยู่ที่คุณสามารถทำได้

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

แต่วิธีที่ฉันเขียนช่วยให้คุณตรวจสอบว่าผู้ใช้ได้ป้องกันการผิดนัดหรือไม่โดยการทำ

var prevented = event.isDefaultPrevented();

สิ่งนี้ช่วยให้คุณฟังคำขอของผู้ใช้ปลายทางเพื่อหยุดการประมวลผลเหตุการณ์เฉพาะเช่นถ้าคุณคลิกองค์ประกอบปุ่มในแบบฟอร์ม แต่ไม่ต้องการให้แบบฟอร์มโพสต์หากมีข้อผิดพลาด


ฉันมักจะฟังเหตุการณ์เช่นนี้

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

คุณสามารถทำได้อีกครั้ง

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

แต่ฉันพบว่าสิ่งนี้ค่อนข้างไม่ปลอดภัยเสมอโดยเฉพาะถ้าคุณทำงานเป็นทีม

ไม่มีอะไรผิดปกติกับสิ่งต่อไปนี้:

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

อย่างไรก็ตามสมมติว่าฉันต้องยกเลิกการเชื่อมโยงเหตุการณ์นี้ด้วยเหตุผลใดก็ตาม (ลองจินตนาการถึงปุ่มที่ปิดใช้งาน) ฉันจะต้องทำ

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

นี้จะลบทุกเหตุการณ์ที่เกิดขึ้นจากeventname $(element)คุณไม่สามารถรู้ได้ว่ามีใครบางคนในอนาคตจะผูกเหตุการณ์กับองค์ประกอบนั้นหรือไม่และคุณจะไม่ผูกพันเหตุการณ์นั้นโดยไม่ตั้งใจเช่นกัน

วิธีที่ปลอดภัยในการหลีกเลี่ยงสิ่งนี้คือการกำหนดเหตุการณ์ของคุณโดยทำ

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

สุดท้ายคุณอาจสังเกตว่าบรรทัดแรกคือ

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

โดยส่วนตัวฉันจะผูกเหตุการณ์ไว้ก่อนที่จะผูกไว้เพื่อให้แน่ใจว่าตัวจัดการเหตุการณ์เดียวกันไม่เคยถูกเรียกหลายครั้ง (ลองคิดดูว่านี่คือปุ่มส่งในแบบฟอร์มการชำระเงินและเหตุการณ์ถูกผูกไว้ 5 ครั้ง)


วิธีการที่ดี +1 สำหรับเนมสเปซ
Aurovrata
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.