jQueryのカスタムイベント?


180

私は、jqueryでカスタムイベント処理を最適な方法で実装する方法についての情報を探しています。「クリック」などのdom要素からイベントをフックする方法は知っていますが、プレビュー機能を処理するための小さなJavaScriptライブラリ/プラグインを構築しています。

取得した一連のルールとデータ/ユーザー入力からdom要素のテキストを更新するスクリプトを実行していますが、このスクリプトでは認識できない他の要素に表示されている同じテキストが必要です。私が必要としているのは、必要なテキストを生成するこのスクリプトを何らかの形で観察するための良いパターンです。

では、どうすればよいですか?ユーザーイベントを発生/処理するためにjqueryのいくつかの組み込み機能を見落としましたか、それを行うためにいくつかのjqueryプラグインが必要ですか?これを処理するための最良の方法/プラグインは何だと思いますか?


3
この質問を見ている人が必要な場合、私の古い問題を実際に解決できるもう1つのフレームワーク、knockoutjs.comがあります。
パーHornshøj-Schierbeck

2
私がこの質問から評判を得続けているのを見て、人々はまだそれを読んでいる必要があります。:私は、クライアントサイドのMVCフレームワークの私の現在の選択更新するangularjs.org
パーHornshøj-Schierbeck

Angular v1とは完全に異なりますが、Angular2(angular.io)は非常に有望であり、beta / rcがなくなると最初に選択します。
パーHornshøj-Schierbeck

回答:


105

これをみて:

http://web.archive.org/webのアーカイブバージョンに基づいて、期限切れのブログページhttp://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/から転載/20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/


jQueryで公開/購読

2008年6月17日

Google Gearsのオフライン機能と統合されたjQuery UIを作成するために、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]);
            }
        });
    };
};

ここでデモを見ることができます。オフラインで動作するようにブラウザーを設定し、何が起こるかを確認してください…。いいえ、それほど刺激的ではありません。

トリガーとバインド

しかし、わくわくするのは(または少なくとも私をわくわくさせるのは)、ステータスがアプリケーションを介して中継される方法です。私は、jQueryのトリガーおよびバインドメソッドを使用してpub / subシステムを実装する、ほとんど議論されていない方法に遭遇しました。

デモコードは必要以上に鈍いです。ネットワーク検出オブジェクトは、それらにアクティブにリッスンするドキュメントに「ステータス」イベントを発行し、次にすべてのサブスクライバーに「通知」イベントを発行します(後で詳しく説明します)。これの背後にある理由は、実際のアプリケーションでは、「通知」イベントがいつ、どのように発行されるかを制御するロジックがおそらく存在することです。

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

jQueryのDOM中心のアプローチのため、イベントはDOM要素に発行(トリガー)されます。これは、一般的なイベントのウィンドウまたはドキュメントオブジェクトにすることも、セレクターを使用してjQueryオブジェクトを生成することもできます。私がデモで取ったアプローチは、サブスクライバーを定義するためのほとんど名前空間の付いたアプローチを作成することです。

サブスクライバーとなるDOM要素は、単に「サブスクライバー」と「networkDetection」で分類されます。次に、通知イベントをトリガーすることにより、これらの要素(デモには1つのみ)にのみイベントを発行できます。$(“.subscriber.networkDetection”)

#notifier一部であるdiv要素.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 2013

1
はい、それは引用です、編集履歴ではこのリンクですが、現在アクセスできません。アーカイブページはこちら
Stano 2013

1
Ben Almanが小さな(tiny tiny tiny)jQuery pub sub pluginを書きました。それは非常にエレガントです。
Barney

127

承認された回答で提供されているリンクは、jQueryを使用してpub / subシステムを実装する良い方法を示していますが、コードを読むのがやや難しいことがわかりました。

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
私はこの答えが本当に好きです。誰でもtrigger()bind()(およびon())に関するドキュメントを読むことができますが、この回答は、jqueryを使用してイベントバス(pub / subシステム)を作成する具体的な例を示しています。
lostdorje 2013年

1
ブラボー。私が知る必要があるすべて。
Patrick Fisher

カスタムイベントをトリガーするときに配列(長さ> 1)を渡すと、リスナーがその引数内のすべての配列項目を取得するため、最終的nに引数の数が増えることがわかりました。
vsync 14年

リスナーでの複数の引数処理のソリューション:var eventData = [].slice.call(arguments).splice(1)
vsync

2
#notifierダミー要素なしでこれを行う方法はありますか?JavaScriptライブラリがあり、オブジェクトがイベントを公開することを望んでいる場合、ページに存在する要素を確認できません。
AaronLS 2014年

21

私はそう思います..(from: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 2013年

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


Chris-関数は完全に機能しました。機能していないのはこの変数にアクセスすることだけです。
Addy

そのバグをしっかりキャッチ。はい、5行目をhandler(ev)から変更すると、to:handler.call(this、ev); その後、この引数は、標準のjqueryイベントハンドラーで通常どおりになります。jsfiddle.net/b9chris/VwEb9
Chris Moschini 2012

これを逆に実装する方法も知っていますか?私はこの例を使用しようとしていますがscroll、伝播しません。リスナーを本文にハードコーディングするのではなくon、イベントを発生させるには、イベントにバインドされた要素が必要だと思います。
Gust van de Wal

あなたが尋ねているシナリオがはっきり分からない。コードサンプルで質問として最もよく聞かれる可能性がありますか?
Chris Moschini、2018年

9

古い投稿ですが、新しい情報で更新していきます。

カスタムイベントを使用するには、それをいくつかのDOM要素にバインドしてトリガーする必要があります。だからあなたは使う必要があります

.on()メソッドは、イベントタイプとイベント処理関数を引数として受け取ります。オプションで、イベント関連データを2番目の引数として受け取り、イベント処理関数を3番目の引数にプッシュすることもできます。渡されたデータはすべて、イベントオブジェクトのdataプロパティのイベント処理関数で使用できます。イベント処理関数は常に最初の引数としてイベントオブジェクトを受け取ります。

そして

.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プレーンなJavaScript では、これを新しい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.