Jquery观察者模式

时间:2012-09-25 19:52:17

标签: javascript jquery observer-pattern

我一直在互联网上查看在jquery中实现观察者模式的例子。

我想要像这样

observer1.observe(subject);
observer2.observe(subject);

为观察者定义一些自定义事件回调

observer1.bind('customEvent', function(contextData) {
  //Some code
});
observer1.bind('anotherCustomEvent', function(contextData) {
  //Some code  
});
observer2.bind('customEvent', function(contextData) {
  //Some code  
});

然后,以下行将触发两个观察者的customEvent回调

subject.trigger('customEvent', contextData);

虽然以下内容只会在observer1上触发anotherCustomEvent,因为observer2没有绑定的自定义事件

subject.trigger('anotherCustomEvent', contextData);

互联网指南更为通用:

$( document ).on( "topicName" , function () {
  //..perform some behaviour
});

$( document ).trigger( "topicName" );

(来自http://addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjquery的示例) 我看不出上面的代码如何用来完成我正在寻找的东西。

要么我必须这样做(如果我保持它像上面的例子):

$(document).on("customEvent", function () {
  observer1.trigger("customEvent");
  observer2.trigger("customEvent");
});

$(subject).click(function() { 
  $(document).trigger("customEvent");
});

或更好一点:

$(subject).click(function() { 
  observer1.trigger("customEvent");
  observer2.trigger("customEvent");
});

无论哪种方式,我都不得不编辑subject-click-callback或document-customEvent-callback,而不是告诉观察者订阅主题。

我是否误解了观察者模式,或者有没有办法实现我正在寻找的东西?

http://addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjavascript在该章中进一步提及发布/订阅模式。这对我来说可能是一种方式,但我错过了示例背后的代码。

3 个答案:

答案 0 :(得分:17)

来自你的评论:

  

当你不得不告诉主题哪些元素由选择器触发而不是具有观察者可以注册的列表的主题

时,我无法看到这是如何实现的。

如果我错了,请纠正我,但你似乎误解了jQuery中如何实现模式。您没有“告诉主题触发哪些元素”,并且主题没有“观察者可以注册的列表”。它的工作原理如下:

  • 主题/发布者发出/触发某些事件(在您定义的某些情况下)。
  • 观察者/订阅者监听某些事件。它保留了它订阅的事件列表。
  • 这些都是基于DOM事件的,所以它受DOM事件模型的限制。

例如,请考虑以下HTML:

<div id="div1">div 1</div>
<div id="div2">div 2</div>

让内部div触发一个名为'custom'的自定义事件。您可以定义何时应该发生这种情况,在此示例中,单击它们时会发生这种情况:

$('div').on('click', function(e) {
    $(this).trigger('custom');
});

现在让我们让document元素订阅该自定义事件:

$(document).on('custom', function(e) {
    console.log('document is handling custom event triggered by ' + e.target.id);
});

当其中一个div触发自定义事件时,将通知观察者/订阅者并将一条消息记录到控制台。

该示例使用document作为观察者,原因是:事件冒出DOM树,并且只能被触发它的祖先元素捕获。由于document是DOM树的根,因此可以查看所有事件。如果#div1是我们的观察者,那么它只会看到由#div1本身触发的事件,而不会由#div2触发的事件触发。

也许这种限制让你感到困惑?


有一些方法可以规避这种限制,但通常情况下,如果您想根据#div1触发的事件对#div2执行某些操作,您只需从已设置的回调中执行此操作即可document元素(或两个div最接近的共同祖先)。无论如何,似乎你真的想要一个替代品,所以这里有一个jQuery插件形式:

$.fn.observe = function(eventName, callback) {
    return this.each(function(){
        var el = this;
        $(document).on(eventName, function(){
            callback.apply(el, arguments);
        })
    });
}

你可以像这样使用它:

$('#div1').observe('custom', function(e) {
    // do something
});

实例:http://jsfiddle.net/JwJsP/1

答案 1 :(得分:0)

可能不是你想要的,但观察者可以订阅听力事件:

        $(document).on('customEvent', '.iObserver', function() {
            console.log('i am observer');
        });

        // add observer
        $('ul li#Observer').addClass('iObserver');

        //remove observer
        $('ul li#Observer').removeClass('iObserver');

答案 2 :(得分:-1)

如果你仍在使用jQuery的事件引擎寻找一些实现,你可以试试这段代码:

//The implementation   
(function($) {

    var o = $({});

    $.each({
        trigger: 'publish',
        on: 'subscribe',
        off: 'unsubscribe'
    }, function(key, val) {
        jQuery[val] = function() {
            o[key].apply(o, arguments);
        };
    });

})(jQuery);


// The way to use it is this:
var somedata = [1, 2, 3, 5, 4, 7, 8];
$.publish('myEvent', somedata); // with data
$.publish('myEvent'); // without data

$.subscribe('myEvent', function(event, data) {
    // handle the event
});